XWiki Platform vulnerable to privilege escalation (PR) from account through like LiveTableResults
Description
XWiki Platform is a generic wiki platform. Starting in version 12.9-rc-1 and prior to versions 14.4.8, 14.10.6, and 15.1, any logged in user can add dangerous content in their first name field and see it executed with programming rights. Leading to rights escalation. The vulnerability has been fixed on XWiki 14.4.8, 14.10.6, and 15.1. As a workaround, one may apply the patch manually.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-like-uiMaven | >= 12.9-rc-1, < 14.4.8 | 14.4.8 |
org.xwiki.platform:xwiki-platform-like-uiMaven | >= 14.5, < 14.10.6 | 14.10.6 |
org.xwiki.platform:xwiki-platform-like-uiMaven | >= 15.0-rc-1, < 15.1 | 15.1 |
Affected products
1- Range: >= 12.9-rc-1, < 14.4.8
Patches
26ce2d04a5779XWIKI-19900: Liked page whose FULLNAME contains dot(.) can not show in user profile.
3 files changed · +126 −1
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/pom.xml+27 −0 modified@@ -70,5 +70,32 @@ <scope>runtime</scope> <optional>true</optional> </dependency> + <!-- Test dependencies. --> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-test-page</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-web-templates</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-like-api</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-user-default</artifactId> + <version>${project.version}</version> + <scope>test</scope> + <type>test-jar</type> + </dependency> </dependencies> </project>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/Code/LiveTableResultPage.xml+1 −1 modified@@ -36,7 +36,7 @@ <minorEdit>false</minorEdit> <syntaxId>xwiki/2.1</syntaxId> <hidden>true</hidden> - <content>{{velocity}} + <content>{{velocity wiki="false"}} #if ($xcontext.action == 'get') #template('hierarchy_macros.vm') #if("$!{request.xpage}" == 'plain')
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/test/java/org/xwiki/like/LiveTableResultPagePageTest.java+98 −0 added@@ -0,0 +1,98 @@ +/* + * 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.like; + +import java.util.List; + +import javax.inject.Named; + +import org.junit.jupiter.api.Test; +import org.xwiki.like.script.LikeScriptServiceComponentList; +import org.xwiki.model.reference.DocumentReference; +import org.xwiki.model.script.ModelScriptService; +import org.xwiki.ratings.RatingsManager; +import org.xwiki.ratings.internal.DefaultRating; +import org.xwiki.rendering.syntax.Syntax; +import org.xwiki.template.script.TemplateScriptService; +import org.xwiki.test.annotation.ComponentList; +import org.xwiki.test.junit5.mockito.MockComponent; +import org.xwiki.test.page.PageTest; +import org.xwiki.test.page.XWikiSyntax21ComponentList; +import org.xwiki.user.UserReferenceComponentList; + +import com.xpn.xwiki.doc.XWikiDocument; + +import net.sf.json.JSONObject; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.Mockito.when; + +/** + * Test of {@code XWiki.Like.Code.LiveTableResultPage}. + * + * @version $Id$ + * @since 15.1 + * @since 14.10.6 + */ +@XWikiSyntax21ComponentList +@LikeScriptServiceComponentList +@UserReferenceComponentList +@ComponentList({ + TemplateScriptService.class, + ModelScriptService.class +}) +class LiveTableResultPagePageTest extends PageTest +{ + private static final DocumentReference DOCUMENT_REFERENCE = + new DocumentReference("xwiki", List.of("XWiki", "Like", "Code"), "LiveTableResultPage"); + + @MockComponent + @Named("solr") + private RatingsManager ratingsManager; + + @Test + void likedPageWithADot() throws Exception + { + DocumentReference likedPageReference = new DocumentReference("xwiki", "Space", "With.ADot"); + + // Create an empty page to be returned as a liked page. + XWikiDocument likedDocument = this.xwiki.getDocument(likedPageReference, this.context); + this.xwiki.saveDocument(likedDocument, this.context); + + // The rating manager is mocked for now as the focus of the tests is currently not to test the likes indexing. + when(this.ratingsManager.getRatings(anyMap(), anyInt(), anyInt(), any(RatingsManager.RatingQueryField.class), + anyBoolean())).thenReturn(List.of(new DefaultRating("id1").setReference(likedPageReference))); + + setOutputSyntax(Syntax.PLAIN_1_0); + this.context.setAction("get"); + + this.request.put("offset", "1"); + this.request.put("reqNo", "1"); + this.request.put("limit", "10"); + + JSONObject object = renderJSONPage(DOCUMENT_REFERENCE); + + assertEquals("xwiki:Space.With\\.ADot", object.getJSONArray("rows").getJSONObject(0).getString("doc_fullName")); + } +}
0993a7ab3c10XWIKI-17733: Use a LiveTable to display the page liked in user profile
15 files changed · +298 −42
xwiki-platform-core/pom.xml+8 −3 modified@@ -494,24 +494,29 @@ <new>method java.util.Optional<org.xwiki.ratings.Rating> org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new> <justification>Redesign of Ratings API: use new best practices for script service return if type is nullable.</justification> </item> - <item> + <item> <code>java.method.parameterTypeChanged</code> <old>parameter org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(===org.xwiki.model.reference.DocumentReference===, org.xwiki.model.reference.DocumentReference, int)</old> <new>parameter java.util.Optional<org.xwiki.ratings.Rating> org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(===org.xwiki.model.reference.EntityReference===, org.xwiki.user.UserReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new> <justification>Redesign of Ratings API: allow to set rating for any reference (not only DocumentReference)</justification> </item> - <item> + <item> <code>java.method.parameterTypeChanged</code> <old>parameter org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(org.xwiki.model.reference.DocumentReference, ===org.xwiki.model.reference.DocumentReference===, int)</old> <new>parameter java.util.Optional<org.xwiki.ratings.Rating> org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, ===org.xwiki.user.UserReference===, int) @ org.xwiki.ratings.script.RatingsScriptService</new> <justification>Redesign of Ratings API: use new best practices for specifying a user by using the UserReference.</justification> </item> - <item> + <item> <code>java.method.returnTypeChanged</code> <old>method org.xwiki.ratings.script.RatingApi org.xwiki.ratings.script.RatingsScriptService::setRating(org.xwiki.model.reference.DocumentReference, org.xwiki.model.reference.DocumentReference, int)</old> <new>method java.util.Optional<org.xwiki.ratings.Rating> org.xwiki.ratings.script.AbstractScriptRatingsManager::setRating(org.xwiki.model.reference.EntityReference, org.xwiki.user.UserReference, int) @ org.xwiki.ratings.script.RatingsScriptService</new> <justification>Redesign of Ratings API: use new best practices for script service return if type is nullable.</justification> </item> + <item> + <code>java.method.addedToInterface</code> + <new>method long org.xwiki.like.LikeManager::countUserLikes(org.xwiki.user.UserReference) throws org.xwiki.like.LikeException</new> + <justification>Unstable API.</justification> + </item> </revapi.ignore> </analysisConfiguration> </configuration>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/internal/DefaultLikeManager.java+13 −9 modified@@ -34,8 +34,6 @@ import org.xwiki.cache.CacheManager; import org.xwiki.cache.config.LRUCacheConfiguration; import org.xwiki.component.annotation.Component; -import org.xwiki.component.manager.ComponentLifecycleException; -import org.xwiki.component.phase.Disposable; import org.xwiki.component.phase.Initializable; import org.xwiki.component.phase.InitializationException; import org.xwiki.like.LikeConfiguration; @@ -65,7 +63,7 @@ */ @Component @Singleton -public class DefaultLikeManager implements LikeManager, Initializable, Disposable +public class DefaultLikeManager implements LikeManager, Initializable { private static final int DEFAULT_LIKE_VOTE = 1; @@ -126,12 +124,6 @@ public void initialize() throws InitializationException } } - @Override - public void dispose() throws ComponentLifecycleException - { - //this.authorizationManager. - } - private String getExistCacheKey(UserReference source, EntityReference target) { return String.format("%s_%s", @@ -176,6 +168,18 @@ public List<EntityReference> getUserLikes(UserReference source, int offset, int } } + @Override + public long countUserLikes(UserReference source) throws LikeException + { + try { + return this.ratingsManager.countRatings( + Collections.singletonMap(RatingsManager.RatingQueryField.USER_REFERENCE, source)); + } catch (RatingsException e) { + throw new LikeException( + String.format("Error when trying to count user likes for user [%s]", source), e); + } + } + @Override public long getEntityLikes(EntityReference target) throws LikeException {
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/LikeManager.java+13 −0 modified@@ -58,6 +58,17 @@ public interface LikeManager */ List<EntityReference> getUserLikes(UserReference source, int offset, int limit) throws LikeException; + /** + * Retrieve the total number of likes performed by a user. + * + * @param source the user who performs the likes to count. + * @return the total number of likes performed. + * @throws LikeException in case of problem when getting the information. + * @since 12.9RC1 + */ + @Unstable + long countUserLikes(UserReference source) throws LikeException; + /** * Retrieve like information a specific entity. * @@ -95,7 +106,9 @@ public interface LikeManager * @param limit the limit used for pagination. * @return a list of user references of users who liked this page. * @throws LikeException in case of problem for performing the query. + * @since 12.9RC1 */ + @Unstable List<UserReference> getLikers(EntityReference target, int offset, int limit) throws LikeException; /**
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/java/org/xwiki/like/script/LikeScriptService.java+20 −0 modified@@ -214,6 +214,26 @@ public List<EntityReference> getUserLikes(UserReference userReference, int offse return Collections.emptyList(); } + /** + * Count the number of likes performed by the given user. + * + * @param userReference the user for whom to count likes. + * @return the number of likes performed. + * @since 12.9RC1 + */ + @Unstable + public Optional<Long> countUserLikes(UserReference userReference) + { + Optional<Long> result = Optional.empty(); + try { + result = Optional.of(this.likeManager.countUserLikes(userReference)); + } catch (LikeException e) { + this.logger.warn("Error while counting likes for user [{}]", userReference, + ExceptionUtils.getRootCause(e)); + } + return result; + } + /** * Determine if the current user already liked the given reference. * @param entityReference the reference for which to check if the current liked it or not already.
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/main/resources/templates/likers.vm+91 −14 modified@@ -17,19 +17,96 @@ ## Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ## 02110-1301 USA, or see the FSF site: http://www.fsf.org. ## --------------------------------------------------------------------------- -#set ($likers = $services.like.getLikers($doc, 0, 50)) -<div id="document-title"><h1>$services.localization.render('like.likers.title', [$doc.title])</h1></div> -<div id="likers-content"> - #if ($likers.isEmpty()) - $services.localization.render('like.likers.empty') +#if ($request.livetable == "true") + #macro (displayUserAliasWithAvatar $userReference $disabled) + <div class="user#if ($disabled) disabled#end" data-reference="$escapetool.xml($userReference)"> + <span class="user-avatar-wrapper"> + #getUserAvatarURL($userReference $avatarURL 120) + <img class="user-avatar" src="$escapetool.xml($avatarURL.url)" /> + </span> + <a href="$xwiki.getURL($userReference)">$escapetool.xml($userReference.name)</a> + </div> + #end + $response.setContentType('application/json') + #set ($documentReference = $doc.documentReference) + ##============================== + ## Offset = item # at which to start displaying data + ##============================== + #set($offset = $numbertool.toNumber($request.get('offset'))) + ## offset starts from 0 in velocity and 1 in javascript + #set($offset = $offset - 1) + #if($offset < 0) + #set($offset = 0) + #end + ##================== + ## Limit = # of items to display + ##================== + #set($limit = $numbertool.toNumber($request.get('limit'))) + ##========== + ## Sort direction + ##========== + #set($order = "$!request.sort") + #if($order != '') + #set($orderDirection = "$!{request.get('dir').toLowerCase()}") + #if("$!orderDirection" != '' && "$!orderDirection" != 'asc') + #set($orderDirection = 'desc') + #end + #end + #set ($likeRecords = $services.like.getLikers($documentReference, $offset, $limit)) + #set ($userRows = []) + #foreach($userReference in $likeRecords) + #set ($grayed = $xcontext.userReference == $userReference.reference) + #set ($userDoc = $xwiki.getDocument($userReference.reference)) + #set ($userProperties = $services.user.getProperties($userReference)) + #set ($userObject = $user.getObject('XWiki.XWikiUsers')) + #set ($row = { + 'grayed': $grayed, + 'doc_fullName': $userDoc.fullName, + 'doc_wiki': $userDoc.wiki, + 'doc_url': $userDoc.getURL(), + 'doc_viewable': $services.security.authorization.hasAccess('view', $userDoc.documentReference), + 'name': "#displayUserAliasWithAvatar($userDoc.documentReference $disabled)", + 'first_name': $userProperties.firstName, + 'last_name': $userProperties.lastName + }) + #set ($discard = $userRows.add($row)) + #end + ## === + ## JSON + ## === + #set ($newOffset = $offset + 1) + #set ($optLikesNumber = $services.like.getLikes($documentReference)) + #if ($optLikesNumber.isPresent()) + #set ($totalRows = $optLikesNumber.get()) #else - <p> - $services.localization.render('like.likers.number', [$likers.size()]) - </p> - <ul> - #foreach($liker in $likers) - <li>#displayUserLink($liker)</li> - #end - </ul> + #set ($totalRows = $likeRecords.size()) #end -</div> \ No newline at end of file + { + "totalrows": $totalRows, + "returnedrows": $likeRecords.size(), + "offset": $newOffset, + "reqNo": $numbertool.toNumber($request.reqNo), + "rows": $jsontool.serialize($userRows) + } +#else + <h1>$escapetool.xml($services.localization.render('like.likers.title', [$doc.plainTitle]))</h1> + #set($columns = ["name", "first_name", "last_name"]) + #set($columnsProperties = { + "name" : { "type" : "text", "sortable": false, "filterable": false, "html": true }, + "first_name" : { "type" : "text", "sortable": false, "filterable": false}, + "last_name" : { "type" : "text", "sortable": false, "filterable": false} + }) + #set ($queryParams = { + "livetable": "true", + "xpage": "likers", + "outputSyntax": "plain" + }) + ## We rely on the same column name than the Users administration, so we use same translation prefix for now. + #set($options = { + 'url': $doc.getURL('get', $escapetool.url($queryParams)), + 'outputOnlyHtml': true, + 'translationPrefix' : "xe.admin.users." + }) + + #livetable("likers" $columns $columnsProperties $options) +#end \ No newline at end of file
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/test/java/org/xwiki/like/internal/DefaultLikeManagerTest.java+10 −0 modified@@ -308,4 +308,14 @@ void getLikers() throws Exception assertEquals(Arrays.asList(userReference1, userReference2, userReference3), this.defaultLikeManager.getLikers(this.target, 12, 4)); } + + @Test + void countUserLikes() throws Exception + { + when(this.ratingsManager.countRatings( + Collections.singletonMap(RatingsManager.RatingQueryField.USER_REFERENCE, this.userReference))) + .thenReturn(42L); + + assertEquals(42L, this.defaultLikeManager.countUserLikes(this.userReference)); + } }
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-api/src/test/java/org/xwiki/like/script/LikeScriptServiceTest.java+20 −0 modified@@ -20,6 +20,7 @@ package org.xwiki.like.script; import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.Optional; @@ -54,6 +55,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -284,4 +286,22 @@ void cleanCache() Locale.ROOT); verify(this.asyncRendererCache).cleanCache(uixReference); } + + @Test + void countUserLikes() throws LikeException + { + when(this.likeManager.countUserLikes(userReference)).thenReturn(43L); + assertEquals(Optional.of(43L), this.likeScriptService.countUserLikes(this.userReference)); + } + + @Test + void getUserLikes() throws LikeException + { + List<EntityReference> expectedList = Arrays.asList( + mock(EntityReference.class), + mock(EntityReference.class), + mock(EntityReference.class)); + when(this.likeManager.getUserLikes(this.userReference, 2, 32)).thenReturn(expectedList); + assertEquals(expectedList, this.likeScriptService.getUserLikes(this.userReference, 2, 32)); + } }
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.de.xml+0 −1 modified@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton="Gefällt mir" Schaltfläc XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Die "Gefällt mir" Schaltfläche immer anzeigen - selbst wenn der Nutzer kein Recht hat diese zu benutzen. Anschalten, um die Anzahl der "Gefällt mir" immer anzuzeigen. XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache-Größe XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Anzahl der "Gefällt mir"-Informationen im Cache. Sie müssen XWiki neustarten, damit veränderte Einstellungen angewendet werden.</content> - </xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.es.xml+0 −1 modified@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Mostrar siempre el botón XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Mostrar el botón incluso si el usuario no tiene derecho de interaccionar con él. Úsalo si deseas mostrar siempre el contador de "Me gusta". XWiki.Like.LikeConfigurationClass_cacheCapacity=Capacidad de la caché XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Número de información de "Me gusta" guardada en la caché. Ten en cuenta que tienes que reiniciar XWiki para que se activen los cambios de esta opción.</content> - </xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.fr.xml+0 −1 modified@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Toujours afficher le bouto XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Afficher le bouton même si l'utilisateur n'a pas les droits pour intéragir avec. Utilisez cette option si vous souhaitez toujours afficher le compteur de J'aime. XWiki.Like.LikeConfigurationClass_cacheCapacity=Capacité du Cache XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Nombre d'information J'aime à conserver dans le cache. Notez que vous devrez redémarrer XWiki pour que cette option soit prise en compte.</content> - </xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.no.xml+0 −1 modified@@ -57,5 +57,4 @@ XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Vis alltid Liker-knappen XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Vis knappen selv om brukeren ikke har rettigheter til å bruke den. Bruk hvis du alltid vil vise Liker-telleren. XWiki.Like.LikeConfigurationClass_cacheCapacity=Hurtigbufferkapasitet XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Antall Liker-informasjon som er lagret i hurtigbufferen. Merk at du må starte XWiki på nytt for at dette valget skal aktiveres.</content> - </xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ru.xml+0 −1 modified@@ -57,5 +57,4 @@ like.newlike.error=Ошибка при попытке поставить "Нра ### Missing: XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Display the button even if the user doesn't have the rights to interact with it. Use it if you wish to always display the Likes counter. ### Missing: XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache capacity ### Missing: XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=Number of Like information kept in cache. Note that you have to restart XWiki for this option change to be taken into account.</content> - </xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.xml+4 −1 modified@@ -52,7 +52,10 @@ like.button.title.like=Click to like the current page. Number of likes on this p like.button.title.unlike=Click to unlike the current page. Number of likes on this page: {0}. like.likers.empty=No one likes this page yet. like.likers.number={0} person(s) like this page: -like.likers.title=Likes on {0} +like.likers.title=Likers of {0} +like.livetable.column.title=Title +like.livetable.column.location=Location +like.livetable.column.likes=Likes XWiki.Like.LikeConfigurationClass_alwaysDisplayButton=Always display Like button XWiki.Like.LikeConfigurationClass_alwaysDisplayButton.hint=Display the button even if the user doesn't have the rights to interact with it. Use it if you wish to always display the Likes counter. XWiki.Like.LikeConfigurationClass_cacheCapacity=Cache capacity
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeViewersMenuUIX.xml+1 −1 modified@@ -183,4 +183,4 @@ <scope>wiki</scope> </property> </object> -</xwikidoc> \ No newline at end of file +</xwikidoc>
xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml+118 −9 modified@@ -36,7 +36,96 @@ <minorEdit>false</minorEdit> <syntaxId>xwiki/2.1</syntaxId> <hidden>true</hidden> - <content/> + <content>{{velocity}} +#if ($request.livetable == "true") + #template('hierarchy_macros.vm') + #if("$!{request.xpage}" == 'plain') + $response.setContentType('application/json') + #end + #set ($documentReference = $services.model.resolveDocument($request.user)) + ##============================== + ## Offset = item # at which to start displaying data + ##============================== + #set($offset = $numbertool.toNumber($request.get('offset'))) + ## offset starts from 0 in velocity and 1 in javascript + #set($offset = $offset - 1) + #if($offset < 0) + #set($offset = 0) + #end + ##================== + ## Limit = # of items to display + ##================== + #set($limit = $numbertool.toNumber($request.get('limit'))) + #set ($likedPages = $services.like.getUserLikes($documentReference, $offset, $limit)) + #set ($optUserLikes = $services.like.countUserLikes($documentReference)) + #if ($optUserLikes.isPresent()) + #set ($totalRows = $optUserLikes.get()) + #else + #set ($totalRows = $likedPages.size()) + #end + ##========== + ## Sort direction + ##========== + #set($order = "$!request.sort") + #if($order != '') + #set($orderDirection = "$!{request.get('dir').toLowerCase()}") + #if("$!orderDirection" != '' && "$!orderDirection" != 'asc') + #set($orderDirection = 'desc') + #end + #end + #set ($pagesRows = []) + #foreach($likedPage in $likedPages) + #set ($likedDoc = $xwiki.getDocument($likedPage)) + #set ($optDocumentLikes = $services.like.getLikes($likedPage)) + #if ($optDocumentLikes.isPresent()) + #set ($documentLikes = $optDocumentLikes.get()) + #else + #set ($documentLikes = "N/A") + #end + ## code inspired from getdocuments.vm + #set ($viewable = $xwiki.hasAccessLevel('view', $xcontext.user, $services.model.serialize($likedPage, "default"))) + #set ($row = {'doc_viewable' : $viewable}) + #if (!$viewable) + #set ($discard = $row.put('doc_fullName', $likedDoc.fullName)) + #else + #set ($translatedDoc = $likedDoc.translatedDocument) + #set ($fullname = $services.model.serialize($likedDoc.documentReference, 'default')) + #set ($discard = $row.put('doc_name', $likedDoc.documentReference.name)) + #set ($discard = $row.put('doc_fullName', $fullname)) + #set ($location = "#hierarchy($likedDoc.documentReference, {'limit': 5, 'plain': false, 'local': true, 'displayTitle': false})") + #set ($discard = $row.put('doc_location', $location)) + #set ($discard = $row.put('doc_space', $likedDoc.space)) + #set ($discard = $row.put('doc_url', $xwiki.getURL($likedDoc))) + #set ($discard = $row.put('doc_space_url', $xwiki.getURL($services.model.createDocumentReference($!likedDoc.wiki, $!likedDoc.space, 'WebHome')))) + #set ($discard = $row.put('doc_wiki', $likedDoc.wiki)) + #set ($discard = $row.put('doc_wiki_url', $xwiki.getURL($services.model.resolveDocument('', 'default', $likedDoc.documentReference.extractReference('WIKI'))))) + #set ($discard = $row.put('doc_author_url', $xwiki.getURL($translatedDoc.author))) + #set ($discard = $row.put('doc_date', $xwiki.formatDate($translatedDoc.date))) + #set ($discard = $row.put('doc_title', $translatedDoc.plainTitle)) + #set ($rawTitle = $translatedDoc.title) + #if ($rawTitle != $row['doc_title']) + #set ($discard = $row.put('doc_title_raw', $rawTitle)) + #end + #set ($discard = $row.put('doc_author', $xwiki.getUserName($translatedDoc.author, false))) + #set ($discard = $row.put('doc_creationDate', $xwiki.formatDate($translatedDoc.creationDate))) + #set ($discard = $row.put('doc_creator', $xwiki.getUserName($translatedDoc.creator, false))) + #end + #set ($discard = $row.put('like', $documentLikes)) + #set ($discard = $pagesRows.add($row)) + #end + #set ($newOffset = $offset + 1) + ## === + ## JSON + ## === + { + "totalrows": $totalRows, + "returnedrows": $pagesRows.size(), + "offset": $newOffset, + "reqNo": $numbertool.toNumber($request.reqNo), + "rows": $jsontool.serialize($pagesRows) + } +#end +{{/velocity}}</content> <object> <name>XWiki.Like.UserProfileUIX</name> <number>0</number> @@ -66,6 +155,8 @@ <cache>0</cache> <disabled>0</disabled> <displayType>select</displayType> + <freeText>forbidden</freeText> + <largeStorage>0</largeStorage> <multiSelect>1</multiSelect> <name>async_context</name> <number>4</number> @@ -154,21 +245,39 @@ </property> <property> <async_context> + <value>doc.reference</value> <value>user</value> - <value>wiki</value> </async_context> </property> <property> - <async_enabled>1</async_enabled> + <async_enabled>0</async_enabled> </property> <property> <content>{{velocity}} -#set ($likedReferences = $services.like.getUserLikes($services.user.currentUserReference, 0, 50)) -|=Page -#foreach ($likeReference in $likedReferences) - #set ($likedDocument = $xwiki.getDocument($likeReference)) - |[[$likedDocument.title>>$services.model.serialize($likeReference)]] -#end +=$escapetool.xml($services.localization.render("like.userprofile.menu"))= +#set($columns = ["doc.title", "doc.location", "like"]) +#set ($docTitleDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.title'))) +#set ($docLocationDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.location'))) +#set ($likesDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.likes'))) +#set($columnsProperties = { + "doc.title" : { "displayName": $docTitleDisplayName, "type": "text", "size": 30, "link": "view", "sortable": false, "filterable": false }, + "doc.location" : { "displayName": $docLocationDisplayName, "type": "text", "size": 30, "html": true, "sortable": false, "filterable": false }, + "like" : { "displayName": $likesDisplayName, "type" : "number", "sortable": false, "filterable": false } +}) + +#set ($currentUser = $services.model.serialize($doc.documentReference, "default")) +#set ($pageToCallReference = $services.model.resolveDocument("XWiki.Like.UserProfileUIX")) +#set ($pageToCall = $xwiki.getDocument($pageToCallReference)) +#set ($queryParams = { + "user": $currentUser, + "livetable": "true", + "xpage": "plain", + "outputSyntax": "plain" +}) +#set($options = { + 'url': $pageToCall.getURL('get', $escapetool.url($queryParams)) +}) +#livetable("likedPages" $columns $columnsProperties $options) {{/velocity}}</content> </property> <property>
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-rf8j-q39g-7xfmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-35152ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/0993a7ab3c102f9ac37ffe361a83a3dc302c0e45ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/6ce2d04a5779e07f6d3ed3f37d4761049b4fc3acghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-rf8j-q39g-7xfmghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-19900ghsax_refsource_MISCWEB
- jira.xwiki.org/browse/XWIKI-20611ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.