VYPR
Critical severityNVD Advisory· Published Jun 23, 2023· Updated Nov 29, 2024

XWiki Platform vulnerable to privilege escalation (PR) from view right via Invitation application

CVE-2023-35150

Description

XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. Starting in version 2.40m-2 and prior to versions 14.4.8, 14.10.4, and 15.0, any user with view rights on any document can execute code with programming rights, leading to remote code execution by crafting an url with a dangerous payload. The problem has been patched in XWiki 15.0, 14.10.4 and 14.4.8.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.xwiki.platform:xwiki-platform-invitation-uiMaven
>= 2.4-m-2, < 14.4.814.4.8
org.xwiki.platform:xwiki-platform-invitation-uiMaven
>= 14.5, < 14.10.414.10.4
org.xwiki.platform:xwiki-platform-invitation-uiMaven
>= 15.0-rc-1, < 15.015.0

Affected products

1

Patches

1
b65220a4d86b

XWIKI-20285: Improve escaping of the Invitation Application

https://github.com/xwiki/xwiki-platformManuel LeducJan 24, 2023via ghsa
50 files changed · +1253 134
  • xwiki-platform-core/pom.xml+16 0 modified
    @@ -179,6 +179,22 @@
                     </item>
                   </differences>
                 </revapi.differences>
    +            <revapi.differences>
    +              <justification>Moved to xwiki-platform-index-default</justification>
    +              <criticality>allowed</criticality>
    +              <differences>
    +                <item>
    +                  <ignore>true</ignore>
    +                  <code>java.class.removed</code>
    +                  <old>class org.xwiki.index.migration.R140300000XWIKI19614DataMigration</old>
    +                </item>
    +                <item>
    +                  <ignore>true</ignore>
    +                  <code>java.class.removed</code>
    +                  <old>class org.xwiki.index.migration.R140300001XWIKI19571DataMigration</old>
    +                </item>
    +              </differences>
    +            </revapi.differences>
               </analysisConfiguration>
             </configuration>
           </plugin>
    
  • xwiki-platform-core/xwiki-platform-extension/xwiki-platform-extension-handlers/xwiki-platform-extension-handler-xar/src/main/java/org/xwiki/extension/xar/internal/DefaultXARExtensionIndex.java+56 0 added
    @@ -0,0 +1,56 @@
    +/*
    + * 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.extension.xar.internal;
    +
    +import javax.inject.Inject;
    +import javax.inject.Named;
    +import javax.inject.Singleton;
    +
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.extension.repository.InstalledExtensionRepository;
    +import org.xwiki.extension.xar.internal.handler.XarExtensionHandler;
    +import org.xwiki.extension.xar.internal.repository.XarInstalledExtensionRepository;
    +import org.xwiki.internal.extension.XARExtensionIndex;
    +import org.xwiki.model.reference.DocumentReference;
    +
    +/**
    + * Default implementation of {@link XARExtensionIndex}. Uses {@link XarInstalledExtensionRepository} to implement the
    + * operations.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@Component
    +@Singleton
    +public class DefaultXARExtensionIndex implements XARExtensionIndex
    +{
    +    @Inject
    +    @Named(XarExtensionHandler.TYPE)
    +    private InstalledExtensionRepository installedXARs;
    +
    +    @Override
    +    public boolean isExtensionDocument(DocumentReference documentReference)
    +    {
    +        return !((XarInstalledExtensionRepository) this.installedXARs).getXarInstalledExtensions(documentReference)
    +            .isEmpty();
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-extension/xwiki-platform-extension-handlers/xwiki-platform-extension-handler-xar/src/main/resources/META-INF/components.txt+1 0 modified
    @@ -1,4 +1,5 @@
     org.xwiki.extension.xar.internal.DefaultXarExtensionConfiguration
    +org.xwiki.extension.xar.internal.DefaultXARExtensionIndex
     org.xwiki.extension.xar.internal.delete.DocumentsDeletingListener
     org.xwiki.extension.xar.internal.doc.XarDocumentRevisionProvider
     org.xwiki.extension.xar.internal.doc.InstalledExtensionDocumentCustomizationDetector
    
  • xwiki-platform-core/xwiki-platform-index/pom.xml+1 0 modified
    @@ -33,6 +33,7 @@
       <description>XWiki Platform - Index - Parent POM</description>
       <modules>
         <module>xwiki-platform-index-api</module>
    +    <module>xwiki-platform-index-default</module>
         <module>xwiki-platform-index-ui</module>
         <module>xwiki-platform-index-tree</module>
       </modules>
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-api/pom.xml+4 34 modified
    @@ -32,7 +32,7 @@
       <description>API to queue asynchronous tasks dedicated to the analysis of wiki pages.</description>
       <packaging>jar</packaging>
       <properties>
    -    <xwiki.jacoco.instructionRatio>0.85</xwiki.jacoco.instructionRatio>
    +    <xwiki.jacoco.instructionRatio>0.04</xwiki.jacoco.instructionRatio>
         <!-- Name to display by the Extension Manager -->
         <xwiki.extension.name>Index API</xwiki.extension.name>
         <xwiki.extension.category>api</xwiki.extension.category>
    @@ -50,15 +50,9 @@
           <version>${project.version}</version>
         </dependency>
         <dependency>
    -      <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-query-manager</artifactId>
    -      <version>${project.version}</version>
    -    </dependency>
    -    <!-- Required to have access to XWikiDocumentIndexingTask. -->
    -    <dependency>
    -      <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-oldcore</artifactId>
    -      <version>${project.version}</version>
    +      <groupId>org.xwiki.commons</groupId>
    +      <artifactId>xwiki-commons-stability</artifactId>
    +      <version>${commons.version}</version>
         </dependency>
         <!-- Test dependencies. -->
         <dependency>
    @@ -67,29 +61,5 @@
           <version>${commons.version}</version>
           <scope>test</scope>
         </dependency>
    -    <dependency>
    -      <groupId>javax.servlet</groupId>
    -      <artifactId>javax.servlet-api</artifactId>
    -      <scope>test</scope>
    -    </dependency>
       </dependencies>
    -  <build>
    -    <plugins>
    -      <plugin>
    -        <!-- Apply the Checkstyle configurations defined in the top level pom.xml file -->
    -        <groupId>org.apache.maven.plugins</groupId>
    -        <artifactId>maven-checkstyle-plugin</artifactId>
    -        <executions>
    -          <execution>
    -            <!-- Specify the "default" execution id so that the "blocker" one is always executed -->
    -            <id>default</id>
    -            <configuration>
    -              <failsOnError>true</failsOnError>
    -              <suppressionsLocation>${basedir}/src/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
    -            </configuration>
    -          </execution>
    -        </executions>
    -      </plugin>
    -    </plugins>
    -  </build>
     </project>
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-api/src/main/java/org/xwiki/index/TaskConsumerScriptService.java+3 5 modified
    @@ -23,14 +23,12 @@
     
     import javax.inject.Inject;
     import javax.inject.Named;
    -import javax.inject.Provider;
     import javax.inject.Singleton;
     
     import org.xwiki.component.annotation.Component;
     import org.xwiki.script.service.ScriptService;
     import org.xwiki.stability.Unstable;
    -
    -import com.xpn.xwiki.XWikiContext;
    +import org.xwiki.wiki.descriptor.WikiDescriptorManager;
     
     /**
      * Provides the operations to interact with the task consumer from the scripts.
    @@ -48,13 +46,13 @@ public class TaskConsumerScriptService implements ScriptService
         private TaskManager taskManager;
     
         @Inject
    -    private Provider<XWikiContext> xcontextProvider;
    +    private WikiDescriptorManager wikiDescriptorManager;
     
         /**
          * @return the count of queued tasks, grouped by task type
          */
         public Map<String, Long> getQueueSizePerType()
         {
    -        return this.taskManager.getQueueSizePerType(this.xcontextProvider.get().getWikiId());
    +        return this.taskManager.getQueueSizePerType(this.wikiDescriptorManager.getCurrentWikiId());
         }
     }
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-api/src/main/resources/META-INF/components.txt+0 8 modified
    @@ -1,9 +1 @@
    -org.xwiki.index.internal.DefaultTasksManager
    -org.xwiki.index.internal.TasksStore
    -org.xwiki.index.internal.TaskExecutor
    -org.xwiki.index.internal.TaskApplicationReadyListener
    -org.xwiki.index.internal.DefaultLinksTaskConsumer
    -org.xwiki.index.internal.listener.LinksUpdateListener
    -org.xwiki.index.migration.R140300000XWIKI19614DataMigration
    -org.xwiki.index.migration.R140300001XWIKI19571DataMigration
     org.xwiki.index.TaskConsumerScriptService
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-api/src/test/java/org/xwiki/index/TaskConsumerScriptServiceTest.java+3 10 modified
    @@ -21,16 +21,12 @@
     
     import java.util.Map;
     
    -import javax.inject.Provider;
    -
     import org.junit.jupiter.api.BeforeEach;
     import org.junit.jupiter.api.Test;
    -import org.mockito.Mock;
     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.XWikiContext;
    +import org.xwiki.wiki.descriptor.WikiDescriptorManager;
     
     import static org.junit.jupiter.api.Assertions.assertEquals;
     import static org.mockito.Mockito.when;
    @@ -51,16 +47,13 @@ class TaskConsumerScriptServiceTest
         private TaskManager taskManager;
     
         @MockComponent
    -    private Provider<XWikiContext> xcontextProvider;
    +    private WikiDescriptorManager wikiDescriptorManager;
     
    -    @Mock
    -    private XWikiContext xcontext;
     
         @BeforeEach
         void setUp()
         {
    -        when(this.xcontextProvider.get()).thenReturn(this.xcontext);
    -        when(this.xcontext.getWikiId()).thenReturn("xwiki");
    +        when(this.wikiDescriptorManager.getCurrentWikiId()).thenReturn("xwiki");
         }
     
         @Test
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/pom.xml+87 0 added
    @@ -0,0 +1,87 @@
    +<?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-index</artifactId>
    +    <version>15.1-SNAPSHOT</version>
    +  </parent>
    +  <artifactId>xwiki-platform-index-default</artifactId>
    +  <name>XWiki Platform - Index - Default</name>
    +  <description>Default implementation of the API to queue asynchronous tasks dedicated to the analysis of wiki pages.</description>
    +  <packaging>jar</packaging>
    +  <properties>
    +    <xwiki.jacoco.instructionRatio>0.84</xwiki.jacoco.instructionRatio>
    +    <!-- Name to display by the Extension Manager -->
    +    <xwiki.extension.name>Default implementation of the Index API</xwiki.extension.name>
    +  </properties>
    +  <dependencies>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-index-api</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.platform</groupId>
    +      <artifactId>xwiki-platform-oldcore</artifactId>
    +      <version>${project.version}</version>
    +    </dependency>
    +    <!-- Test dependencies. -->
    +    <dependency>
    +      <groupId>org.xwiki.commons</groupId>
    +      <artifactId>xwiki-commons-tool-test-component</artifactId>
    +      <version>${commons.version}</version>
    +      <scope>test</scope>
    +    </dependency>
    +    <dependency>
    +      <groupId>javax.servlet</groupId>
    +      <artifactId>javax.servlet-api</artifactId>
    +      <scope>test</scope>
    +    </dependency>
    +  </dependencies>
    +  <build>
    +    <plugins>
    +      <plugin>
    +        <!-- Apply the Checkstyle configurations defined in the top level pom.xml file -->
    +        <groupId>org.apache.maven.plugins</groupId>
    +        <artifactId>maven-checkstyle-plugin</artifactId>
    +        <executions>
    +          <execution>
    +            <!-- Specify the "default" execution id so that the "blocker" one is always executed -->
    +            <id>default</id>
    +            <configuration>
    +              <failsOnError>true</failsOnError>
    +              <suppressionsLocation>${basedir}/src/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
    +            </configuration>
    +          </execution>
    +        </executions>
    +      </plugin>
    +    </plugins>
    +  </build>
    +</project>
    \ No newline at end of file
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/checkstyle/checkstyle-suppressions.xml+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/DefaultLinksTaskConsumer.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/DefaultTasksManager.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/jmx/JMXTasks.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/jmx/JMXTasksMBean.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/listener/LinksUpdateListener.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/TaskApplicationReadyListener.java+1 2 renamed
    @@ -27,7 +27,6 @@
     import org.xwiki.bridge.event.ApplicationReadyEvent;
     import org.xwiki.component.annotation.Component;
     import org.xwiki.component.phase.Initializable;
    -import org.xwiki.component.phase.InitializationException;
     import org.xwiki.index.TaskManager;
     import org.xwiki.observation.AbstractEventListener;
     import org.xwiki.observation.event.Event;
    @@ -73,7 +72,7 @@ public void onEvent(Event event, Object source, Object data)
         }
     
         @Override
    -    public void initialize() throws InitializationException
    +    public void initialize()
         {
             // If the application is already initialized we start the threads immediately (e.g. in case of extension
             // install) and the implementation of type DefaultTasksManager.
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/TaskExecutor.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/internal/TasksStore.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/migration/R140300000XWIKI19614DataMigration.java+31 39 renamed
    @@ -21,21 +21,19 @@
     
     import java.util.List;
     
    -import javax.inject.Inject;
     import javax.inject.Named;
    -import javax.inject.Provider;
     import javax.inject.Singleton;
     
     import org.xwiki.component.annotation.Component;
    -import org.xwiki.index.TaskManager;
    +import org.xwiki.internal.migration.AbstractDocumentsMigration;
     import org.xwiki.query.Query;
     import org.xwiki.query.QueryException;
    -import org.xwiki.query.QueryManager;
     
    +import com.xpn.xwiki.XWiki;
     import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.doc.XWikiDocument;
     import com.xpn.xwiki.store.migration.DataMigrationException;
     import com.xpn.xwiki.store.migration.XWikiDBVersion;
    -import com.xpn.xwiki.store.migration.hibernate.HibernateDataMigration;
     
     import static org.xwiki.index.internal.DefaultLinksTaskConsumer.LINKS_TASK_TYPE;
     
    @@ -46,27 +44,17 @@
      * @since 14.2RC1
      * @deprecated link storage and indexing moved to Solr (implemented in xwiki-platform-search-solr-api)
      */
    -// TODO: Implement DataMigration once XWIKI-19399 is fixed.
     @Component
     @Singleton
     @Named(R140300000XWIKI19614DataMigration.HINT)
     @Deprecated(since = "14.8RC1")
    -public class R140300000XWIKI19614DataMigration implements HibernateDataMigration
    +public class R140300000XWIKI19614DataMigration extends AbstractDocumentsMigration
     {
         /**
          * The hint for this component.
          */
         public static final String HINT = "R140300000XWIKI19614";
     
    -    @Inject
    -    private QueryManager queryManager;
    -
    -    @Inject
    -    private TaskManager taskManager;
    -
    -    @Inject
    -    private Provider<XWikiContext> contextProvider;
    -
         @Override
         public String getName()
         {
    @@ -86,43 +74,47 @@ public XWikiDBVersion getVersion()
         }
     
         @Override
    -    public void migrate() throws DataMigrationException
    +    protected String getTaskType()
    +    {
    +        return LINKS_TASK_TYPE;
    +    }
    +
    +    @Override
    +    protected List<String> selectDocuments() throws DataMigrationException
         {
    -        XWikiContext context = this.contextProvider.get();
    -        // No need to migrate if the wiki does not support backlinks.
    +        List<String> documents;
    +        XWikiContext context = getXWikiContext();
    +        XWiki wiki = getXWikiContext().getWiki();
             if (context.getWiki().hasBacklinks(context)) {
    -            String wikiId = context.getWikiId();
                 try {
    -                List<Long> ids =
    -                    this.queryManager.createQuery("SELECT doc.id FROM XWikiDocument doc", Query.HQL).setWiki(wikiId)
    -                        .execute();
    -                for (Long id : ids) {
    -                    this.taskManager.addTask(wikiId, id, LINKS_TASK_TYPE);
    -                }
    +                documents = wiki.getStore().getQueryManager()
    +                    .createQuery("SELECT doc.fullName FROM XWikiDocument doc", Query.HQL)
    +                    .setWiki(context.getWikiId())
    +                    .execute();
                 } catch (QueryException e) {
                     throw new DataMigrationException(
    -                    String.format("Failed retrieve the list of all the documents for wiki [%s].", wikiId), e);
    +                    String.format("Failed retrieve the list of all the documents for wiki [%s].", wiki.getName()), e);
                 }
    +        } else {
    +            documents = List.of();
             }
    +        return documents;
         }
     
         @Override
    -    public boolean shouldExecute(XWikiDBVersion startupVersion)
    +    protected void logBeforeQueuingTask(XWikiDocument document)
         {
    -        return true;
    +        // No logs here as it would be too verbose (all documents of the wiki are queued).
         }
     
         @Override
    -    public String getPreHibernateLiquibaseChangeLog()
    +    protected void logBeforeQueuingTasks(List<XWikiDocument> documents)
         {
    -        // TODO: Remove once XWIKI-19399 is fixed.
    -        return null;
    -    }
    -
    -    @Override
    -    public String getLiquibaseChangeLog()
    -    {
    -        // TODO: Remove once XWIKI-19399 is fixed.
    -        return null;
    +        XWikiContext context = getXWikiContext();
    +        if (context.getWiki().hasBacklinks(context)) {
    +            super.logBeforeQueuingTasks(documents);
    +        } else {
    +            this.logger.info("Skipped because backlinks are not supported on [{}]", context.getWikiId());
    +        }
         }
     }
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/java/org/xwiki/index/migration/R140300001XWIKI19571DataMigration.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/main/resources/META-INF/components.txt+8 0 added
    @@ -0,0 +1,8 @@
    +org.xwiki.index.internal.DefaultTasksManager
    +org.xwiki.index.internal.TasksStore
    +org.xwiki.index.internal.TaskExecutor
    +org.xwiki.index.internal.TaskApplicationReadyListener
    +org.xwiki.index.internal.DefaultLinksTaskConsumer
    +org.xwiki.index.internal.listener.LinksUpdateListener
    +org.xwiki.index.migration.R140300000XWIKI19614DataMigration
    +org.xwiki.index.migration.R140300001XWIKI19571DataMigration
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/internal/DefaultLinksTaskConsumerTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/internal/DefaultTasksManagerTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/internal/listener/LinksUpdateListenerTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/internal/TaskExecutorTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/internal/TasksStoreTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/migration/R140300000XWIKI19614DataMigrationTest.java+53 10 renamed
    @@ -21,27 +21,37 @@
     
     import java.util.List;
     
    -import javax.inject.Provider;
    -
     import org.junit.jupiter.api.BeforeEach;
     import org.junit.jupiter.api.Test;
    +import org.junit.jupiter.api.extension.RegisterExtension;
     import org.mockito.Mock;
    +import org.xwiki.context.Execution;
    +import org.xwiki.context.ExecutionContext;
     import org.xwiki.index.TaskManager;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.model.reference.DocumentReferenceResolver;
     import org.xwiki.query.Query;
     import org.xwiki.query.QueryException;
     import org.xwiki.query.QueryManager;
    +import org.xwiki.test.LogLevel;
    +import org.xwiki.test.junit5.LogCaptureExtension;
     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.XWiki;
     import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.doc.XWikiDocument;
    +import com.xpn.xwiki.store.XWikiStoreInterface;
     import com.xpn.xwiki.store.migration.DataMigrationException;
     import com.xpn.xwiki.store.migration.hibernate.HibernateDataMigration;
     
    +import ch.qos.logback.classic.Level;
    +
     import static org.junit.jupiter.api.Assertions.assertEquals;
     import static org.junit.jupiter.api.Assertions.assertThrows;
     import static org.mockito.ArgumentMatchers.any;
    +import static org.mockito.Mockito.mock;
     import static org.mockito.Mockito.verify;
     import static org.mockito.Mockito.verifyNoInteractions;
     import static org.mockito.Mockito.when;
    @@ -58,14 +68,20 @@ class R140300000XWIKI19614DataMigrationTest
         @InjectMockComponents(role = HibernateDataMigration.class)
         private R140300000XWIKI19614DataMigration migration;
     
    -    @MockComponent
    +    @Mock
         private QueryManager queryManager;
     
         @MockComponent
         private TaskManager taskManager;
     
         @MockComponent
    -    private Provider<XWikiContext> contextProvider;
    +    private Execution execution;
    +
    +    @MockComponent
    +    private DocumentReferenceResolver<String> resolver;
    +
    +    @RegisterExtension
    +    LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.INFO);
     
         @Mock
         private XWikiContext context;
    @@ -79,26 +95,48 @@ class R140300000XWIKI19614DataMigrationTest
         @BeforeEach
         void setUp() throws Exception
         {
    -        when(this.contextProvider.get()).thenReturn(this.context);
    +        ExecutionContext executionContext = mock(ExecutionContext.class);
    +        XWikiStoreInterface xWikiStoreInterface = mock(XWikiStoreInterface.class);
    +
    +        when(this.execution.getContext()).thenReturn(executionContext);
    +        when(executionContext.getProperty("xwikicontext")).thenReturn(this.context);
             when(this.context.getWiki()).thenReturn(this.wiki);
    +        when(this.wiki.getName()).thenReturn("wiki1");
             when(this.context.getWikiId()).thenReturn("wiki1");
    -        when(this.queryManager.createQuery("SELECT doc.id FROM XWikiDocument doc",
    +        when(this.wiki.getStore()).thenReturn(xWikiStoreInterface);
    +        when(xWikiStoreInterface.getQueryManager()).thenReturn(this.queryManager);
    +
    +        when(this.queryManager.createQuery("SELECT doc.fullName FROM XWikiDocument doc",
                 Query.HQL)).thenReturn(this.query);
             when(this.query.setWiki(any())).thenReturn(this.query);
         }
     
         @Test
         void migrate() throws Exception
         {
    +        DocumentReference doc42 = new DocumentReference("xwiki", "XWiki", "Doc42");
    +        DocumentReference doc43 = new DocumentReference("xwiki", "XWiki", "Doc43");
    +        XWikiDocument xWikiDocument42 = mock(XWikiDocument.class);
    +        XWikiDocument xWikiDocument43 = mock(XWikiDocument.class);
    +
             when(this.wiki.hasBacklinks(this.context)).thenReturn(true);
     
    -        when(this.query.execute()).thenReturn(List.of(42L, 43L));
    +        when(this.query.execute()).thenReturn(List.of("xwiki.XWiki.Doc42", "xwiki.XWiki.Doc43"));
    +        when(this.resolver.resolve("xwiki.XWiki.Doc42")).thenReturn(doc42);
    +        when(this.resolver.resolve("xwiki.XWiki.Doc43")).thenReturn(doc43);
    +        when(this.wiki.getDocument(doc42, this.context)).thenReturn(xWikiDocument42);
    +        when(this.wiki.getDocument(doc43, this.context)).thenReturn(xWikiDocument43);
    +        when(xWikiDocument42.getId()).thenReturn(42L);
    +        when(xWikiDocument43.getId()).thenReturn(43L);
     
             this.migration.migrate();
     
             verify(this.query).setWiki("wiki1");
    -        verify(this.taskManager).addTask("wiki1", 42L,  "links");
    +        verify(this.taskManager).addTask("wiki1", 42L, "links");
             verify(this.taskManager).addTask("wiki1", 43L, "links");
    +
    +        assertEquals("[2] documents queued to task [links]", this.logCapture.getMessage(0));
    +        assertEquals(Level.INFO, this.logCapture.getLogEvent(0).getLevel());
         }
     
         @Test
    @@ -111,8 +149,11 @@ void migrateQueryException() throws Exception
             DataMigrationException queryException =
                 assertThrows(DataMigrationException.class, () -> this.migration.migrate());
     
    -        assertEquals("Failed retrieve the list of all the documents for wiki [wiki1].", queryException.getMessage());
    -        assertEquals(QueryException.class, queryException.getCause().getClass());
    +        assertEquals("Data migration R140300000XWIKI19614 failed", queryException.getMessage());
    +        assertEquals("Failed retrieve the list of all the documents for wiki [wiki1].",
    +            queryException.getCause().getMessage());
    +        assertEquals(DataMigrationException.class, queryException.getCause().getClass());
    +        assertEquals(QueryException.class, queryException.getCause().getCause().getClass());
     
             verify(this.query).setWiki("wiki1");
             verifyNoInteractions(this.taskManager);
    @@ -125,5 +166,7 @@ void migrateNotHasBacklinks() throws Exception
             this.migration.migrate();
             verifyNoInteractions(this.queryManager);
             verifyNoInteractions(this.taskManager);
    +        assertEquals("Skipped because backlinks are not supported on [wiki1]", this.logCapture.getMessage(0));
    +        assertEquals(Level.INFO, this.logCapture.getLogEvent(0).getLevel());
         }
     }
    
  • xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-default/src/test/java/org/xwiki/index/migration/R140300001XWIKI19571DataMigrationTest.java+0 0 renamed
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationCommon.xml+11 5 modified
    @@ -57,7 +57,9 @@
       {{info}}testLoadInvitationConfig{{/info}}
       #testLoadInvitationConfig()
     #elseif($doc.documentReference.name == 'InvitationCommon')
    -  {{info}}$services.localization.render('xe.invitation.internalDocument', ["${doc.getSpace()}.WebHome"]){{/info}}
    +  #set ($linkTarget = "${doc.getSpace()}.WebHome")
    +  #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
    +  {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
     #end
     ##
     #*
    @@ -186,8 +188,10 @@
             $config.put($element.getName(), $defaultConfigObj.getProperty($element.getName()).getValue())
           #end
           ##
    -      #set($configDocContent = '{{velo' + 'city}}{{info}}$services.localization.render(''xe.invitation.internalDocument'', ["'
    -                               + "$!config.get('mainPage')" + '"]){{/info}}{{/velo' + 'city}}')
    +      #set($configDocContent = 
    +        '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
    +          + '[$services.rendering.escape("' + "$!config.get('mainPage')" 
    +          + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
           $configDoc.setContent($configDocContent)
           $configDoc.setParent($configClassNameInternal)
           #set($configObj = $configDoc.newObject($configClassNameInternal))
    @@ -275,8 +279,10 @@
     #macro(loadInvitationMail, $config, $emailContainer, $mail)
       ## If this doesn't already exist, it's created.
       #if($emailContainer.isNew())
    -    #set($emailContainerContent = '{{velo' + 'city}}{{info}}$services.localization.render(''xe.invitation.internalDocument'', ["'
    -                                  + "$config.get('emailContainer')" + '"]){{/info}}{{/velo' + 'city}}')
    +    #set($emailContainerContent = 
    +      '{{velocity}}{{info}}$services.localization.render(''xe.invitation.internalDocument'','
    +        + '[$services.rendering.escape("' + "$config.get('emailContainer')" 
    +        + '", ''xwiki/2.1'')]){{/info}}{{/velocity}}')
         #set($discard = $emailContainer.setContent($emailContainerContent))
         #set($discard = $emailContainer.setHidden(true))
         #set($discard = $emailContainer.saveAsAuthor())
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationConfig.xml+2 2 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.4" reference="Invitation.InvitationConfig" locale="">
    +<xwikidoc version="1.5" reference="Invitation.InvitationConfig" locale="">
       <web>Invitation</web>
       <name>InvitationConfig</name>
       <language/>
    @@ -34,7 +34,7 @@
       <title/>
       <comment/>
       <minorEdit>false</minorEdit>
    -  <syntaxId>xwiki/2.0</syntaxId>
    +  <syntaxId>xwiki/2.1</syntaxId>
       <hidden>true</hidden>
       <content>{{velocity}}{{info}}$services.localization.render('xe.invitation.internalDocument', ['Invitation.WebHome']){{/info}}{{/velocity}}</content>
       <attachment>
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationGuestActions.xml+6 4 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.3" reference="Invitation.InvitationGuestActions" locale="">
    +<xwikidoc version="1.5" reference="Invitation.InvitationGuestActions" locale="">
       <web>Invitation</web>
       <name>InvitationGuestActions</name>
       <language/>
    @@ -34,9 +34,9 @@
       <title/>
       <comment/>
       <minorEdit>false</minorEdit>
    -  <syntaxId>xwiki/2.0</syntaxId>
    +  <syntaxId>xwiki/2.1</syntaxId>
       <hidden>true</hidden>
    -  <content>{{include reference="Invitation.InvitationCommon" /}}
    +  <content>{{include reference="Invitation.InvitationCommon"/}}
     
     {{velocity}}
     #*
    @@ -93,7 +93,9 @@
                 $mail,
                 $emailContainer)
     #else
    -  {{info}}$services.localization.render('xe.invitation.internalDocument', ["${doc.getSpace()}.WebHome"]){{/info}}
    +  #set ($linkTarget = "${doc.getSpace()}.WebHome")
    +  #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
    +  {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
     #end
     ##
     ##---------------------------------------------------------------------
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationMailClass.xml+8 4 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.3" reference="Invitation.InvitationMailClass" locale="">
    +<xwikidoc version="1.5" reference="Invitation.InvitationMailClass" locale="">
       <web>Invitation</web>
       <name>InvitationMailClass</name>
       <language/>
    @@ -34,9 +34,13 @@
       <title>InvitationMailClass</title>
       <comment/>
       <minorEdit>false</minorEdit>
    -  <syntaxId>xwiki/2.0</syntaxId>
    +  <syntaxId>xwiki/2.1</syntaxId>
       <hidden>true</hidden>
    -  <content>{{velocity}}{{info}}$services.localization.render('xe.invitation.internalDocument', ["${doc.getSpace()}.WebHome"]){{/info}}{{/velocity}}</content>
    +  <content>{{velocity}}
    +  #set ($linkTarget = "${doc.getSpace()}.WebHome")
    +  #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
    +  {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
    +{{/velocity}}</content>
       <class>
         <name>Invitation.InvitationMailClass</name>
         <customClass/>
    @@ -121,10 +125,10 @@
           <number>3</number>
           <picker>1</picker>
           <prettyName>sendingUser</prettyName>
    -      <size>30</size>
           <relationalStorage>0</relationalStorage>
           <separator> </separator>
           <separators/>
    +      <size>30</size>
           <sort>none</sort>
           <unmodifiable>0</unmodifiable>
           <usesList>0</usesList>
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationMemberActions.xml+7 5 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.3" reference="Invitation.InvitationMemberActions" locale="">
    +<xwikidoc version="1.5" reference="Invitation.InvitationMemberActions" locale="">
       <web>Invitation</web>
       <name>InvitationMemberActions</name>
       <language/>
    @@ -34,11 +34,11 @@
       <title>$services.localization.render('xe.invitation.tools.heading')</title>
       <comment/>
       <minorEdit>false</minorEdit>
    -  <syntaxId>xwiki/2.0</syntaxId>
    +  <syntaxId>xwiki/2.1</syntaxId>
       <hidden>true</hidden>
    -  <content>{{include reference="Invitation.InvitationCommon" /}}
    +  <content>{{include reference="Invitation.InvitationCommon"/}}
     
    -{{include reference="Invitation.InvitationMembersCommon" /}}
    +{{include reference="Invitation.InvitationMembersCommon"/}}
     
     {{velocity}}
     #*
    @@ -120,7 +120,9 @@ $xwiki.get('ssx').use($config.get('commonPage'))
       #else
         ##
         ## No orders, Lets just explain what this page is for.
    -    {{info}}$services.localization.render('xe.invitation.internalDocument', ["${doc.getSpace()}.WebHome"]){{/info}}
    +    #set ($linkTarget = "${doc.getSpace()}.WebHome")
    +    #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
    +    {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
       #end
     #end
     ##
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/main/resources/Invitation/InvitationMembersCommon.xml+5 3 modified
    @@ -20,7 +20,7 @@
      * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
     -->
     
    -<xwikidoc version="1.3" reference="Invitation.InvitationMembersCommon" locale="">
    +<xwikidoc version="1.5" reference="Invitation.InvitationMembersCommon" locale="">
       <web>Invitation</web>
       <name>InvitationMembersCommon</name>
       <language/>
    @@ -34,7 +34,7 @@
       <title/>
       <comment/>
       <minorEdit>false</minorEdit>
    -  <syntaxId>xwiki/2.0</syntaxId>
    +  <syntaxId>xwiki/2.1</syntaxId>
       <hidden>true</hidden>
       <content>{{velocity}}
     #*
    @@ -53,7 +53,9 @@
      * Macros also depend on other macros but only other macros which are contained in this script.
      *###
     #if($doc.documentReference.name == 'InvitationMembersCommon')
    -  {{info}}$services.localization.render('xe.invitation.internalDocument', ["${doc.getSpace()}.WebHome"]){{/info}}
    +  #set ($linkTarget = "${doc.getSpace()}.WebHome")
    +  #set ($linkTarget = $services.rendering.escape($linkTarget, 'xwiki/2.1'))
    +  {{info}}$services.localization.render('xe.invitation.internalDocument', [$linkTarget]){{/info}}
     #end
     ##
     #*
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationCommonPageTest.java+2 2 modified
    @@ -89,11 +89,11 @@ void setUp() throws Exception
         void testEq0() throws Exception
         {
             this.context.setDoc(this.xwiki.getDocument(
    -            new DocumentReference("xwiki", "<script>console.log</script>", "InvitationCommon"), this.context));
    +            new DocumentReference("xwiki", "]]  {{noscript/}}", "InvitationCommon"), this.context));
     
             DocumentReference invitationCommonReference = new DocumentReference("xwiki", "Invitation", "InvitationCommon");
             Document document = Jsoup.parse(loadPage(invitationCommonReference).getRenderedContent(this.context));
    -        assertEquals("xe.invitation.internalDocument [<script>console\\.log</script>.WebHome]",
    +        assertEquals("xe.invitation.internalDocument []] {{noscript/}}.WebHome]",
                 document.selectFirst(".infomessage").text());
         }
     
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationConfigPageTest.java+78 0 added
    @@ -0,0 +1,78 @@
    +/*
    + * 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.invitation;
    +
    +import org.jsoup.Jsoup;
    +import org.jsoup.nodes.Document;
    +import org.jsoup.nodes.Element;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration;
    +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource;
    +import org.xwiki.rendering.internal.macro.message.InfoMessageMacro;
    +import org.xwiki.test.annotation.ComponentList;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.TestNoScriptMacro;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@code Invitation.InvitationConfig}.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +@RenderingScriptServiceComponentList
    +@ComponentList({
    +    InfoMessageMacro.class,
    +    TestNoScriptMacro.class,
    +    // Start - Required in addition of RenderingScriptServiceComponentList
    +    DefaultExtendedRenderingConfiguration.class,
    +    RenderingConfigClassDocumentConfigurationSource.class,
    +    // End - Required in additional of RenderingScriptServiceComponentList
    +})
    +class InvitationConfigPageTest extends PageTest
    +{
    +    private static final DocumentReference INVITATION_CONFIG_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationConfig");
    +
    +    @Test
    +    void escapeInfoMessageInternalDocumentParameter() throws Exception
    +    {
    +        XWikiDocument invitationGuestActionsDocument = loadPage(INVITATION_CONFIG_DOCUMENT_REFERENCE);
    +
    +        // Set up the current doc in the context so that $doc is bound in scripts
    +        this.context.setDoc(
    +            this.xwiki.getDocument(new DocumentReference("xwiki", "]] {{noscript/}}", "Page"), this.context));
    +
    +        Document document = Jsoup.parse(invitationGuestActionsDocument.getRenderedContent(this.context));
    +        Element infomessage = document.selectFirst(".infomessage");
    +        assertEquals("xe.invitation.internalDocument [Invitation.WebHome]", infomessage.text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationGuestActionsPageTest.java+88 0 added
    @@ -0,0 +1,88 @@
    +/*
    + * 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.invitation;
    +
    +import org.jsoup.Jsoup;
    +import org.jsoup.nodes.Document;
    +import org.jsoup.nodes.Element;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration;
    +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource;
    +import org.xwiki.rendering.internal.macro.message.InfoMessageMacro;
    +import org.xwiki.test.annotation.ComponentList;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.TestNoScriptMacro;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@code Invitation.InvitationGuestActions}.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +@RenderingScriptServiceComponentList
    +@ComponentList({
    +    InfoMessageMacro.class,
    +    TestNoScriptMacro.class,
    +    // Start - Required in addition of RenderingScriptServiceComponentList
    +    DefaultExtendedRenderingConfiguration.class,
    +    RenderingConfigClassDocumentConfigurationSource.class,
    +    // End - Required in additional of RenderingScriptServiceComponentList
    +})
    +class InvitationGuestActionsPageTest extends PageTest
    +{
    +    private static final DocumentReference INVITATION_COMMON_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationCommon");
    +
    +    private static final DocumentReference INVITATION_GUEST_ACTIONS_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationGuestActions");
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        loadPage(INVITATION_COMMON_DOCUMENT_REFERENCE);
    +    }
    +
    +    @Test
    +    void escapeInfoMessageInternalDocumentParameter() throws Exception
    +    {
    +        XWikiDocument invitationGuestActionsDocument = loadPage(INVITATION_GUEST_ACTIONS_DOCUMENT_REFERENCE);
    +
    +        // Set up the current doc in the context so that $doc is bound in scripts
    +        this.context.setDoc(
    +            this.xwiki.getDocument(new DocumentReference("xwiki", "]] {{noscript/}}", "Page"), this.context));
    +
    +        Document document = Jsoup.parse(invitationGuestActionsDocument.getRenderedContent(this.context));
    +        Element infomessage = document.selectFirst(".infomessage");
    +        assertEquals("xe.invitation.internalDocument []] {{noscript/}}.WebHome]", infomessage.text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationMailClassPageTest.java+78 0 added
    @@ -0,0 +1,78 @@
    +/*
    + * 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.invitation;
    +
    +import org.jsoup.Jsoup;
    +import org.jsoup.nodes.Document;
    +import org.jsoup.nodes.Element;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration;
    +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource;
    +import org.xwiki.rendering.internal.macro.message.InfoMessageMacro;
    +import org.xwiki.test.annotation.ComponentList;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.TestNoScriptMacro;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@code Invitation.InvitationMailClass}.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +@RenderingScriptServiceComponentList
    +@ComponentList({
    +    InfoMessageMacro.class,
    +    TestNoScriptMacro.class,
    +    // Start - Required in addition of RenderingScriptServiceComponentList
    +    DefaultExtendedRenderingConfiguration.class,
    +    RenderingConfigClassDocumentConfigurationSource.class,
    +    // End - Required in additional of RenderingScriptServiceComponentList
    +})
    +class InvitationMailClassPageTest extends PageTest
    +{
    +    private static final DocumentReference INVITATION_MAIL_CLASS_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationMailClass");
    +
    +    @Test
    +    void escapeInfoMessageInternalDocumentParameter() throws Exception
    +    {
    +        XWikiDocument invitationGuestActionsDocument = loadPage(INVITATION_MAIL_CLASS_DOCUMENT_REFERENCE);
    +
    +        // Set up the current doc in the context so that $doc is bound in scripts
    +        this.context.setDoc(
    +            this.xwiki.getDocument(new DocumentReference("xwiki", "]] {{noscript/}}", "Page"), this.context));
    +
    +        Document document = Jsoup.parse(invitationGuestActionsDocument.getRenderedContent(this.context));
    +        Element infomessage = document.selectFirst(".infomessage");
    +        assertEquals("xe.invitation.internalDocument []] {{noscript/}}.WebHome]", infomessage.text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationMemberActionsPageTest.java+91 0 added
    @@ -0,0 +1,91 @@
    +/*
    + * 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.invitation;
    +
    +import org.jsoup.Jsoup;
    +import org.jsoup.nodes.Document;
    +import org.jsoup.nodes.Element;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration;
    +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource;
    +import org.xwiki.rendering.internal.macro.message.InfoMessageMacro;
    +import org.xwiki.test.annotation.ComponentList;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.TestNoScriptMacro;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@code Invitation.InvitationMemberActions}.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +@RenderingScriptServiceComponentList
    +@ComponentList({
    +    InfoMessageMacro.class,
    +    TestNoScriptMacro.class,
    +    // Start - Required in addition of RenderingScriptServiceComponentList
    +    DefaultExtendedRenderingConfiguration.class,
    +    RenderingConfigClassDocumentConfigurationSource.class,
    +    // End - Required in additional of RenderingScriptServiceComponentList
    +})
    +class InvitationMemberActionsPageTest extends PageTest
    +{
    +    private static final DocumentReference INVITATION_COMMON_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationCommon");
    +
    +    private static final DocumentReference INVITATION_MEMBER_ACTIONS_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationMemberActions");
    +
    +    @BeforeEach
    +    void setUp() throws Exception
    +    {
    +        loadPage(INVITATION_COMMON_DOCUMENT_REFERENCE);
    +    }
    +
    +    @Test
    +    void escapeInfoMessageInternalDocumentParameter() throws Exception
    +    {
    +        XWikiDocument invitationGuestActionsDocument = loadPage(INVITATION_MEMBER_ACTIONS_DOCUMENT_REFERENCE);
    +
    +        // Set a non-guest user as otherwise the rendering stops early.
    +        this.context.setUserReference(new DocumentReference("xwiki", "XWiki", "U1"));
    +
    +        // Set up the current doc in the context so that $doc is bound in scripts
    +        this.context.setDoc(
    +            this.xwiki.getDocument(new DocumentReference("xwiki", "]] {{noscript/}}", "Page"), this.context));
    +
    +        Document document = Jsoup.parse(invitationGuestActionsDocument.getRenderedContent(this.context));
    +        Element infomessage = document.selectFirst(".infomessage");
    +        assertEquals("xe.invitation.internalDocument []] {{noscript/}}.WebHome]", infomessage.text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-invitation/xwiki-platform-invitation-ui/src/test/java/org/xwiki/invitation/InvitationMembersCommonPageTest.java+81 0 added
    @@ -0,0 +1,81 @@
    +/*
    + * 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.invitation;
    +
    +import org.jsoup.Jsoup;
    +import org.jsoup.nodes.Document;
    +import org.junit.jupiter.api.Test;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.RenderingScriptServiceComponentList;
    +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration;
    +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource;
    +import org.xwiki.rendering.internal.macro.message.InfoMessageMacro;
    +import org.xwiki.test.annotation.ComponentList;
    +import org.xwiki.test.page.HTML50ComponentList;
    +import org.xwiki.test.page.PageTest;
    +import org.xwiki.test.page.TestNoScriptMacro;
    +import org.xwiki.test.page.XWikiSyntax21ComponentList;
    +
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@code Invitation.InvitationMembersCommon}.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@HTML50ComponentList
    +@XWikiSyntax21ComponentList
    +@RenderingScriptServiceComponentList
    +@ComponentList({
    +    InfoMessageMacro.class,
    +    TestNoScriptMacro.class,
    +    // Start - Required in addition of RenderingScriptServiceComponentList
    +    DefaultExtendedRenderingConfiguration.class,
    +    RenderingConfigClassDocumentConfigurationSource.class,
    +    // End - Required in additional of RenderingScriptServiceComponentList
    +})
    +class InvitationMembersCommonPageTest extends PageTest
    +{
    +    private static final DocumentReference INVITATION_MEMBER_COMMON_DOCUMENT_REFERENCE =
    +        new DocumentReference("xwiki", "Invitation", "InvitationMembersCommon");
    +
    +    @Test
    +    void escapeInfoMessageInternalDocumentParameter() throws Exception
    +    {
    +        XWikiDocument invitationGuestActionsDocument = loadPage(INVITATION_MEMBER_COMMON_DOCUMENT_REFERENCE);
    +
    +        // Set a non-guest user as otherwise the rendering stops early.
    +        this.context.setUserReference(new DocumentReference("xwiki", "XWiki", "U1"));
    +
    +        // Set up the current doc in the context so that $doc is bound in scripts
    +        this.context.setDoc(
    +            this.xwiki.getDocument(new DocumentReference("xwiki", "]] {{noscript/}}", "InvitationMembersCommon"),
    +                this.context));
    +
    +        Document document = Jsoup.parse(invitationGuestActionsDocument.getRenderedContent(this.context));
    +        assertEquals("xe.invitation.internalDocument []] {{noscript/}}.WebHome]",
    +            document.selectFirst(".infomessage").text());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-minimaldependencies/pom.xml+7 0 modified
    @@ -349,6 +349,13 @@
           <version>${project.version}</version>
           <scope>runtime</scope>
         </dependency>
    +    <!-- The default document task analysis implementation -->
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-index-default</artifactId>
    +      <version>${project.version}</version>
    +      <scope>runtime</scope>
    +    </dependency>
     
         <!-- ********************************************************************** -->
         <!-- Plugins, hard to install as extensions (we need to get rid of all that) -->
    
  • xwiki-platform-core/xwiki-platform-oldcore/pom.xml+5 0 modified
    @@ -640,6 +640,11 @@
           <artifactId>apache-el</artifactId>
           <scope>test</scope>
         </dependency>
    +    <dependency>
    +      <groupId>org.xwiki.platform</groupId>
    +      <artifactId>xwiki-platform-index-api</artifactId>
    +      <version>${project.version}</version>
    +    </dependency>
       </dependencies>
       <build>
         <plugins>
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/internal/extension/XARExtensionIndex.java+41 0 added
    @@ -0,0 +1,41 @@
    +/*
    + * 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.internal.extension;
    +
    +import org.xwiki.component.annotation.Role;
    +import org.xwiki.model.reference.DocumentReference;
    +
    +/**
    + * Provides operation to access to information relative to XARs provided by extensions.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@Role
    +public interface XARExtensionIndex
    +{
    +    /**
    +     * @param documentReference a document reference
    +     * @return {@code true} if a given document reference is provided by an extension
    +     */
    +    boolean isExtensionDocument(DocumentReference documentReference);
    +}
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/internal/migration/AbstractDocumentsMigration.java+120 0 added
    @@ -0,0 +1,120 @@
    +/*
    + * 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.internal.migration;
    +
    +import java.util.List;
    +import java.util.Optional;
    +
    +import javax.inject.Inject;
    +
    +import org.slf4j.Logger;
    +import org.xwiki.index.TaskManager;
    +import org.xwiki.model.reference.DocumentReferenceResolver;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.XWikiException;
    +import com.xpn.xwiki.doc.XWikiDocument;
    +import com.xpn.xwiki.store.migration.DataMigrationException;
    +import com.xpn.xwiki.store.migration.hibernate.AbstractHibernateDataMigration;
    +
    +import static java.util.stream.Collectors.toList;
    +
    +/**
    + * Allow to easily queue a document analysis task on a set documents to migrate. Sub-classes need to implement two
    + * methods:
    + * <ul>
    + *     <li>{@link #selectDocuments()}: return the list of document ids to queue for migration</li>
    + *     <li>{@link #getTaskType()}: the type of the task to queue documents to</li>
    + * </ul>
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +public abstract class AbstractDocumentsMigration extends AbstractHibernateDataMigration
    +{
    +    @Inject
    +    protected Logger logger;
    +
    +    @Inject
    +    protected DocumentReferenceResolver<String> documentReferenceResolver;
    +
    +    @Inject
    +    private TaskManager taskManager;
    +
    +    @Override
    +    protected void hibernateMigrate() throws DataMigrationException
    +    {
    +        List<XWikiDocument> documents = selectDocuments()
    +            .stream()
    +            .map(this::convert)
    +            .filter(Optional::isPresent)
    +            .map(Optional::get)
    +            .collect(toList());
    +        logBeforeQueuingTasks(documents);
    +        for (XWikiDocument document : documents) {
    +            logBeforeQueuingTask(document);
    +            this.taskManager.addTask(this.getXWikiContext().getWikiId(), document.getId(), getTaskType());
    +        }
    +    }
    +
    +    private Optional<XWikiDocument> convert(String documentReference)
    +    {
    +        XWikiContext context = getXWikiContext();
    +        try {
    +            return Optional.of(
    +                context.getWiki().getDocument(this.documentReferenceResolver.resolve(documentReference), context));
    +        } catch (XWikiException e) {
    +            this.logger.error("Failed to resolve [{}]", documentReference, e);
    +            return Optional.empty();
    +        }
    +    }
    +
    +    /**
    +     * @return the id of the task type to queue documents to
    +     */
    +    protected abstract String getTaskType();
    +
    +    /**
    +     * @return the list of document ids to migrate
    +     */
    +    protected abstract List<String> selectDocuments() throws DataMigrationException;
    +
    +    /**
    +     * Prints an info log with the number of queued documents and the type of the task.
    +     *
    +     * @param documents the full list of documents that will be queued
    +     */
    +    protected void logBeforeQueuingTasks(List<XWikiDocument> documents)
    +    {
    +        this.logger.info("[{}] documents queued to task [{}]", documents.size(), getTaskType());
    +    }
    +
    +    /**
    +     * Prints an info logs with an individual document and well as its queued task.
    +     *
    +     * @param document a individual document that will be queued
    +     */
    +    protected void logBeforeQueuingTask(XWikiDocument document)
    +    {
    +        this.logger.info("document [{}] queued to task [{}]", document, getTaskType());
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/internal/migration/InvitationInternalDocumentParameterEscapingFixer.java+76 0 added
    @@ -0,0 +1,76 @@
    +/*
    + * 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.internal.migration;
    +
    +import java.util.Objects;
    +import java.util.Optional;
    +import java.util.regex.Pattern;
    +
    +import javax.inject.Singleton;
    +
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.rendering.syntax.Syntax;
    +
    +import static java.util.regex.Matcher.quoteReplacement;
    +
    +/**
    + * Fix a content by looking for localization of {@code xe.invitation.internalDocument} and escaping its parameter. The
    + * translation fixed by this method is initially introduced by the invitation application but the fix is localed in
    + * oldcore so that the fix is applied on pages even if the invitation application has been uninstalled.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@Component(roles = InvitationInternalDocumentParameterEscapingFixer.class)
    +@Singleton
    +public class InvitationInternalDocumentParameterEscapingFixer
    +{
    +    private static final Pattern PATTERN = Pattern.compile("(\\{\\{info}}"
    +        + "\\$services\\.localization\\.render\\('xe\\.invitation\\.internalDocument', \\[)(\"[^\"]+\")(]\\)\\"
    +        + "{\\{/info}})");
    +
    +    /**
    +     * @param content the context to fix
    +     * @param syntax the syntax of the context to fix (xwiki/2.0 or xwiki/2.1)
    +     * @return the context with the fix applied, or {@link Optional#empty()} if nothing needs to be fixed
    +     */
    +    public Optional<String> fix(String content, Syntax syntax)
    +    {
    +        String escapedContent = PATTERN.matcher(content).replaceAll(matchResult -> {
    +            if (matchResult.group(2).contains("services.rendering.escape")) {
    +                return matchResult.group();
    +            } else {
    +                // Concatenate the various groups of the regex while wrapping the localization argument with a
    +                // call to the escaping script service.
    +                String format = String.format("%s$services.rendering.escape(%s, '%s')%s", matchResult.group(1),
    +                    matchResult.group(2), syntax.toIdString(), matchResult.group(3));
    +                return quoteReplacement(format);
    +            }
    +        });
    +
    +        if (Objects.equals(escapedContent, content)) {
    +            return Optional.empty();
    +        } else {
    +            return Optional.of(escapedContent);
    +        }
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/internal/migration/InvitationInternalDocumentParameterEscapingTaskConsumer.java+106 0 added
    @@ -0,0 +1,106 @@
    +/*
    + * 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.internal.migration;
    +
    +import java.util.List;
    +
    +import javax.inject.Inject;
    +import javax.inject.Named;
    +import javax.inject.Provider;
    +import javax.inject.Singleton;
    +
    +import org.slf4j.Logger;
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.index.IndexException;
    +import org.xwiki.index.TaskConsumer;
    +import org.xwiki.model.reference.DocumentReference;
    +import org.xwiki.rendering.syntax.Syntax;
    +
    +import com.xpn.xwiki.XWikiContext;
    +import com.xpn.xwiki.XWikiException;
    +import com.xpn.xwiki.doc.XWikiDocument;
    +
    +/**
    + * Apply {@link InvitationInternalDocumentParameterEscapingFixer} on the documents queued by
    + * {@link R150000000XWIKI20285DataMigration} if applicable, and log the skipped ones. This translation key is initially
    + * introduced by the invitation application but the fix is localed in oldcore so that the fix is applied on pages even
    + * if the invitation application has been uninstalled.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@Component
    +@Singleton
    +@Named(InvitationInternalDocumentParameterEscapingTaskConsumer.HINT)
    +public class InvitationInternalDocumentParameterEscapingTaskConsumer implements TaskConsumer
    +{
    +    /**
    +     * This task consumer hint.
    +     */
    +    public static final String HINT = "internal-document-parameter-escaping";
    +
    +    @Inject
    +    private Logger logger;
    +
    +    @Inject
    +    private Provider<XWikiContext> contextProvider;
    +
    +    @Inject
    +    private InvitationInternalDocumentParameterEscapingFixer invitationInternalDocumentParameterEscapingFixer;
    +
    +    @Override
    +    public void consume(DocumentReference documentReference, String version) throws IndexException
    +    {
    +        try {
    +            XWikiContext context = this.contextProvider.get();
    +            task(context.getWiki().getDocument(documentReference, context));
    +        } catch (XWikiException e) {
    +            throw new IndexException(String.format("Failed to resolve document [%s]", documentReference), e);
    +        }
    +    }
    +
    +    private void task(XWikiDocument document)
    +    {
    +        Syntax syntax = document.getSyntax();
    +        if (List.of(Syntax.XWIKI_2_1, Syntax.XWIKI_2_0).contains(syntax)) {
    +            try {
    +                this.invitationInternalDocumentParameterEscapingFixer.fix(document.getContent(), document.getSyntax())
    +                    .ifPresent(content -> {
    +                        document.setContent(content);
    +                        try {
    +                            XWikiContext context = this.contextProvider.get();
    +                            context.getWiki().saveDocument(document, "Automatic bad escaping fix.", true, context);
    +                            this.logger.info("[{}] successfully fixed.", document);
    +                        } catch (XWikiException e) {
    +                            this.logger.error("Failed to save document [{}]", document, e);
    +                        }
    +                    });
    +            } catch (Exception e) {
    +                this.logger.error("Unexpected error while fixing [{}]", document, e);
    +            }
    +        } else {
    +            this.logger.warn(
    +                "[{}] skipped because escaping for syntax [{}] is not supported. It is advised to review this file.",
    +                document, syntax);
    +        }
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/java/org/xwiki/internal/migration/R150000000XWIKI20285DataMigration.java+97 0 added
    @@ -0,0 +1,97 @@
    +/*
    + * 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.internal.migration;
    +
    +import java.util.List;
    +import java.util.stream.Collectors;
    +
    +import javax.inject.Inject;
    +import javax.inject.Named;
    +import javax.inject.Singleton;
    +
    +import org.xwiki.component.annotation.Component;
    +import org.xwiki.internal.extension.XARExtensionIndex;
    +import org.xwiki.query.QueryException;
    +
    +import com.xpn.xwiki.XWiki;
    +import com.xpn.xwiki.store.migration.DataMigrationException;
    +import com.xpn.xwiki.store.migration.XWikiDBVersion;
    +
    +import static org.xwiki.query.Query.XWQL;
    +
    +/**
    + * Search for documents with a known invalid content produced by code generation (i.e., that cannot be fixed by editing
    + * a xar file), and apply an automatic escaping fix.
    + *
    + * @version $Id$
    + * @since 15.0RC1
    + * @since 14.4.8
    + * @since 14.10.4
    + */
    +@Component
    +@Named("R150000000XWIKI20285")
    +@Singleton
    +public class R150000000XWIKI20285DataMigration extends AbstractDocumentsMigration
    +{
    +    @Inject
    +    private XARExtensionIndex installedXARs;
    +
    +    @Override
    +    public String getDescription()
    +    {
    +        return "Patch the InvitationConfig documents with improper escaping.";
    +    }
    +
    +    @Override
    +    public XWikiDBVersion getVersion()
    +    {
    +        return new XWikiDBVersion(150000000);
    +    }
    +
    +    @Override
    +    protected String getTaskType()
    +    {
    +        return InvitationInternalDocumentParameterEscapingTaskConsumer.HINT;
    +    }
    +
    +    @Override
    +    protected List<String> selectDocuments() throws DataMigrationException
    +    {
    +        XWiki wiki = getXWikiContext().getWiki();
    +        try {
    +            // We select potentially impacted documents using like wildcards. This selection might lead to false 
    +            // positive that wild be filtered out by the more accurate regex in
    +            // InvitationInternalDocumentParameterEscapingFixer.
    +            return wiki.getStore().getQueryManager()
    +                .createQuery("where doc.content "
    +                    + "like '%{{info}}%services.localization.render%xe.invitation.internalDocument%{{/info}}%'", XWQL)
    +                .<String>execute()
    +                .stream()
    +                // Exclude document that are provided by extensions, because they are fixed using the usual xar upgrade
    +                // mechanism.
    +                .filter(documentReference -> !this.installedXARs.isExtensionDocument(
    +                    this.documentReferenceResolver.resolve(documentReference)))
    +                .collect(Collectors.toList());
    +        } catch (QueryException e) {
    +            throw new DataMigrationException(
    +                String.format("Failed retrieve the list of all the documents for wiki [%s].", wiki.getName()), e);
    +        }
    +    }
    +}
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/META-INF/components.txt+3 0 modified
    @@ -267,3 +267,6 @@ com.xpn.xwiki.web.ViewAction
     com.xpn.xwiki.web.ViewAttachRevAction
     2000:org.xwiki.internal.attachment.validation.VoidAttachmentValidator
     org.xwiki.internal.template.ActionTemplateRequirement
    +org.xwiki.internal.migration.R150000000XWIKI20285DataMigration
    +org.xwiki.internal.migration.InvitationInternalDocumentParameterEscapingFixer
    +org.xwiki.internal.migration.InvitationInternalDocumentParameterEscapingTaskConsumer
    
  • xwiki-platform-core/xwiki-platform-oldcore/src/test/java/org/xwiki/internal/migration/InvitationInternalDocumentParameterEscapingFixerTest.java+76 0 added
    @@ -0,0 +1,76 @@
    +/*
    + * 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.internal.migration;
    +
    +import java.util.Optional;
    +import java.util.stream.Stream;
    +
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
    +import org.xwiki.rendering.syntax.Syntax;
    +import org.xwiki.test.junit5.mockito.ComponentTest;
    +import org.xwiki.test.junit5.mockito.InjectMockComponents;
    +
    +import static org.junit.jupiter.api.Assertions.assertEquals;
    +
    +/**
    + * Test of {@link InvitationInternalDocumentParameterEscapingFixer}.
    + *
    + * @version $Id$
    + */
    +@ComponentTest
    +class InvitationInternalDocumentParameterEscapingFixerTest
    +{
    +    @InjectMockComponents
    +    private InvitationInternalDocumentParameterEscapingFixer fixer;
    +
    +    public static Stream<Arguments> fixSource()
    +    {
    +        return Stream.of(
    +            Arguments.of(
    +                "nothing to change 1\n"
    +                    + "{{info}}$services.localization.render('xe.invitation.internalDocument', [$noChange]){{/info}}"
    +                    + "nothing to change 2\n"
    +                    + "{{info}}$services.localization.render('xe.invitation.internalDocument', [\"$change\"]){{/info}}"
    +                    + "nothing to change 3",
    +                Optional.of(
    +                    "nothing to change 1\n"
    +                        + "{{info}}$services.localization.render('xe.invitation.internalDocument', [$noChange]){{/info}}nothing to change 2\n"
    +                        + "{{info}}$services.localization.render('xe.invitation.internalDocument', [$services.rendering.escape(\"$change\", 'xwiki/2.1')]){{/info}}nothing to change 3"
    +                )
    +            ),
    +            Arguments.of(
    +                "nothing to change 1\n"
    +                    + "{{info}}$services.localization.render('xe.invitation.internalDocument', [$noChange]){{/info}}"
    +                    + "nothing to change 2\n"
    +                    + "nothing to change 3",
    +                Optional.empty()
    +            )
    +        );
    +    }
    +
    +    @ParameterizedTest
    +    @MethodSource("fixSource")
    +    void fix(String value, Optional<String> expected)
    +    {
    +        assertEquals(expected, this.fixer.fix(value, Syntax.XWIKI_2_1));
    +    }
    +}
    
  • xwiki-platform-tools/xwiki-platform-tool-packager-plugin/pom.xml+1 1 modified
    @@ -117,7 +117,7 @@
         </dependency>
         <dependency>
           <groupId>org.xwiki.platform</groupId>
    -      <artifactId>xwiki-platform-index-api</artifactId>
    +      <artifactId>xwiki-platform-index-default</artifactId>
           <version>${project.version}</version>
         </dependency>
         <dependency>
    

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

5

News mentions

0

No linked articles in our index yet.