summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2014-09-07 12:53:08 -0400
committerJames Moger <james.moger@gitblit.com>2014-09-07 12:53:08 -0400
commitf7174e6984c08a153d1ba198c4bffe68c5afd873 (patch)
treea4f81f00320a3e962f87714f2e0ee90528beb2e4
parentb8a44784ba8b0aaf9a3fbe6321956c0ee0e0451c (diff)
parent7fdc298cf06c3d88d4fd9fd158fb4d32edac12a0 (diff)
downloadgitblit-f7174e6984c08a153d1ba198c4bffe68c5afd873.tar.gz
gitblit-f7174e6984c08a153d1ba198c4bffe68c5afd873.zip
Merge branch 'ticket/164' into develop
-rw-r--r--.classpath1
-rw-r--r--build.moxie1
-rw-r--r--gitblit.iml11
-rw-r--r--src/main/java/com/gitblit/FederationClient.java5
-rw-r--r--src/main/java/com/gitblit/MigrateTickets.java5
-rw-r--r--src/main/java/com/gitblit/ReindexTickets.java5
-rw-r--r--src/main/java/com/gitblit/guice/CoreModule.java3
-rw-r--r--src/main/java/com/gitblit/manager/GitblitManager.java7
-rw-r--r--src/main/java/com/gitblit/manager/IRuntimeManager.java8
-rw-r--r--src/main/java/com/gitblit/manager/RuntimeManager.java21
-rw-r--r--src/main/java/com/gitblit/utils/JSoupXssFilter.java92
-rw-r--r--src/main/java/com/gitblit/utils/XssFilter.java64
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java14
-rw-r--r--src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java408
-rw-r--r--src/main/java/com/gitblit/wicket/GitblitWicketApp.java3
-rw-r--r--src/main/java/com/gitblit/wicket/MarkupProcessor.java930
-rw-r--r--src/main/java/com/gitblit/wicket/SafeTextModel.java96
-rw-r--r--src/main/java/com/gitblit/wicket/WicketUtils.java5
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/DocPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/DocsPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditTicketPage.java8
-rw-r--r--src/main/java/com/gitblit/wicket/pages/NewTicketPage.java8
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RepositoryPage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/SummaryPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/panels/CommentPanel.java5
-rw-r--r--src/main/java/com/gitblit/wicket/panels/MarkdownTextArea.java6
-rw-r--r--src/test/java/com/gitblit/tests/AuthenticationManagerTest.java5
-rw-r--r--src/test/java/com/gitblit/tests/BranchTicketServiceTest.java6
-rw-r--r--src/test/java/com/gitblit/tests/FileTicketServiceTest.java6
-rw-r--r--src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java8
-rw-r--r--src/test/java/com/gitblit/tests/LdapAuthenticationTest.java8
-rw-r--r--src/test/java/com/gitblit/tests/LuceneExecutorTest.java5
-rw-r--r--src/test/java/com/gitblit/tests/RedisTicketServiceTest.java6
-rw-r--r--src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java8
-rw-r--r--src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java7
36 files changed, 1092 insertions, 684 deletions
diff --git a/.classpath b/.classpath
index 53faa536..61f3a970 100644
--- a/.classpath
+++ b/.classpath
@@ -77,6 +77,7 @@
<classpathentry kind="lib" path="ext/commons-pool2-2.0.jar" sourcepath="ext/src/commons-pool2-2.0.jar" />
<classpathentry kind="lib" path="ext/pf4j-0.9.0.jar" sourcepath="ext/src/pf4j-0.9.0.jar" />
<classpathentry kind="lib" path="ext/tika-core-1.5.jar" sourcepath="ext/src/tika-core-1.5.jar" />
+ <classpathentry kind="lib" path="ext/jsoup-1.7.3.jar" sourcepath="ext/src/jsoup-1.7.3.jar" />
<classpathentry kind="lib" path="ext/junit-4.11.jar" sourcepath="ext/src/junit-4.11.jar" />
<classpathentry kind="lib" path="ext/hamcrest-core-1.3.jar" sourcepath="ext/src/hamcrest-core-1.3.jar" />
<classpathentry kind="lib" path="ext/selenium-java-2.28.0.jar" sourcepath="ext/src/selenium-java-2.28.0.jar" />
diff --git a/build.moxie b/build.moxie
index ea2763c4..6b6c0085 100644
--- a/build.moxie
+++ b/build.moxie
@@ -178,6 +178,7 @@ dependencies:
- compile 'redis.clients:jedis:2.3.1' :war
- compile 'ro.fortsoft.pf4j:pf4j:0.9.0' :war
- compile 'org.apache.tika:tika-core:1.5' :war
+- compile 'org.jsoup:jsoup:1.7.3' :war
- test 'junit'
# Dependencies for Selenium web page testing
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar
diff --git a/gitblit.iml b/gitblit.iml
index 4061daf4..e49bc80e 100644
--- a/gitblit.iml
+++ b/gitblit.iml
@@ -801,6 +801,17 @@
</SOURCES>
</library>
</orderEntry>
+ <orderEntry type="module-library">
+ <library name="jsoup-1.7.3.jar">
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/ext/jsoup-1.7.3.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/ext/src/jsoup-1.7.3.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
<orderEntry type="module-library" scope="TEST">
<library name="junit-4.11.jar">
<CLASSES>
diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java
index 822e8a7f..487080e5 100644
--- a/src/main/java/com/gitblit/FederationClient.java
+++ b/src/main/java/com/gitblit/FederationClient.java
@@ -36,6 +36,8 @@ import com.gitblit.models.Mailing;
import com.gitblit.service.FederationPullService;
import com.gitblit.utils.FederationUtils;
import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Command-line client to pull federated Gitblit repositories.
@@ -92,7 +94,8 @@ public class FederationClient {
}
// configure the Gitblit singleton for minimal, non-server operation
- RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, baseFolder).start();
NoopNotificationManager notifications = new NoopNotificationManager().start();
UserManager users = new UserManager(runtime, null).start();
RepositoryManager repositories = new RepositoryManager(runtime, null, users).start();
diff --git a/src/main/java/com/gitblit/MigrateTickets.java b/src/main/java/com/gitblit/MigrateTickets.java
index ad1c63ea..94284ee2 100644
--- a/src/main/java/com/gitblit/MigrateTickets.java
+++ b/src/main/java/com/gitblit/MigrateTickets.java
@@ -39,6 +39,8 @@ import com.gitblit.tickets.FileTicketService;
import com.gitblit.tickets.ITicketService;
import com.gitblit.tickets.RedisTicketService;
import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* A command-line tool to move all tickets from one ticket service to another.
@@ -134,7 +136,8 @@ public class MigrateTickets {
settings.overrideSetting(Keys.web.activityCacheDays, 0);
settings.overrideSetting(ITicketService.SETTING_UPDATE_DIFFSTATS, false);
- IRuntimeManager runtimeManager = new RuntimeManager(settings, baseFolder).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter, baseFolder).start();
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null, null).start();
String inputServiceName = settings.getString(Keys.tickets.service, BranchTicketService.class.getSimpleName());
diff --git a/src/main/java/com/gitblit/ReindexTickets.java b/src/main/java/com/gitblit/ReindexTickets.java
index 5a614481..858436af 100644
--- a/src/main/java/com/gitblit/ReindexTickets.java
+++ b/src/main/java/com/gitblit/ReindexTickets.java
@@ -33,6 +33,8 @@ import com.gitblit.tickets.FileTicketService;
import com.gitblit.tickets.ITicketService;
import com.gitblit.tickets.RedisTicketService;
import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* A command-line tool to reindex all tickets in all repositories when the
@@ -126,7 +128,8 @@ public class ReindexTickets {
settings.overrideSetting(Keys.git.enableMirroring, false);
settings.overrideSetting(Keys.web.activityCacheDays, 0);
- IRuntimeManager runtimeManager = new RuntimeManager(settings, baseFolder).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter, baseFolder).start();
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null, null).start();
String serviceName = settings.getString(Keys.tickets.service, BranchTicketService.class.getSimpleName());
diff --git a/src/main/java/com/gitblit/guice/CoreModule.java b/src/main/java/com/gitblit/guice/CoreModule.java
index c0d39e99..a942b2ec 100644
--- a/src/main/java/com/gitblit/guice/CoreModule.java
+++ b/src/main/java/com/gitblit/guice/CoreModule.java
@@ -39,7 +39,9 @@ import com.gitblit.manager.ServicesManager;
import com.gitblit.manager.UserManager;
import com.gitblit.tickets.ITicketService;
import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.utils.JSoupXssFilter;
import com.gitblit.utils.WorkQueue;
+import com.gitblit.utils.XssFilter;
import com.google.inject.AbstractModule;
/**
@@ -54,6 +56,7 @@ public class CoreModule extends AbstractModule {
protected void configure() {
bind(IStoredSettings.class).toInstance(new FileSettings());
+ bind(XssFilter.class).to(JSoupXssFilter.class);
// bind complex providers
bind(IPublicKeyManager.class).toProvider(IPublicKeyManagerProvider.class);
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index da081276..6edac453 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -76,6 +76,8 @@ import com.gitblit.tickets.ITicketService;
import com.gitblit.transport.ssh.IPublicKeyManager;
import com.gitblit.transport.ssh.SshKey;
import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.HttpUtils;
import com.gitblit.utils.JsonUtils;
import com.gitblit.utils.ObjectCache;
import com.gitblit.utils.StringUtils;
@@ -591,6 +593,11 @@ public class GitblitManager implements IGitblit {
return runtimeManager.getInjector();
}
+ @Override
+ public XssFilter getXssFilter() {
+ return runtimeManager.getXssFilter();
+ }
+
/*
* NOTIFICATION MANAGER
*/
diff --git a/src/main/java/com/gitblit/manager/IRuntimeManager.java b/src/main/java/com/gitblit/manager/IRuntimeManager.java
index 8322d34f..2203b7ff 100644
--- a/src/main/java/com/gitblit/manager/IRuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/IRuntimeManager.java
@@ -24,6 +24,7 @@ import java.util.TimeZone;
import com.gitblit.IStoredSettings;
import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
+import com.gitblit.utils.XssFilter;
import com.google.inject.Injector;
public interface IRuntimeManager extends IManager {
@@ -118,4 +119,11 @@ public interface IRuntimeManager extends IManager {
* @since 1.4.0
*/
boolean updateSettings(Map<String, String> updatedSettings);
+
+ /**
+ * Returns the HTML sanitizer used to clean user content.
+ *
+ * @return the HTML sanitizer
+ */
+ XssFilter getXssFilter();
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/RuntimeManager.java b/src/main/java/com/gitblit/manager/RuntimeManager.java
index 95a363f6..18d6b9c2 100644
--- a/src/main/java/com/gitblit/manager/RuntimeManager.java
+++ b/src/main/java/com/gitblit/manager/RuntimeManager.java
@@ -32,6 +32,7 @@ import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.XssFilter;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
@@ -43,6 +44,8 @@ public class RuntimeManager implements IRuntimeManager {
private final IStoredSettings settings;
+ private final XssFilter xssFilter;
+
private final ServerStatus serverStatus;
private final ServerSettings settingsModel;
@@ -55,14 +58,15 @@ public class RuntimeManager implements IRuntimeManager {
private Injector injector;
@Inject
- public RuntimeManager(IStoredSettings settings) {
- this(settings, null);
+ public RuntimeManager(IStoredSettings settings, XssFilter xssFilter) {
+ this(settings, xssFilter, null);
}
- public RuntimeManager(IStoredSettings settings, File baseFolder) {
+ public RuntimeManager(IStoredSettings settings, XssFilter xssFilter, File baseFolder) {
this.settings = settings;
this.settingsModel = new ServerSettings();
this.serverStatus = new ServerStatus();
+ this.xssFilter = xssFilter;
this.baseFolder = baseFolder == null ? new File("") : baseFolder;
}
@@ -229,4 +233,15 @@ public class RuntimeManager implements IRuntimeManager {
serverStatus.heapFree = Runtime.getRuntime().freeMemory();
return serverStatus;
}
+
+ /**
+ * Returns the XSS filter.
+ *
+ * @return the XSS filter
+ */
+ @Override
+ public XssFilter getXssFilter() {
+ return xssFilter;
+ }
+
}
diff --git a/src/main/java/com/gitblit/utils/JSoupXssFilter.java b/src/main/java/com/gitblit/utils/JSoupXssFilter.java
new file mode 100644
index 00000000..a0b3da21
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/JSoupXssFilter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.utils;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.safety.Cleaner;
+import org.jsoup.safety.Whitelist;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * Implementation of an XSS filter based on JSoup.
+ *
+ * @author James Moger
+ *
+ */
+@Singleton
+public class JSoupXssFilter implements XssFilter {
+
+ private final Cleaner none;
+
+ private final Cleaner relaxed;
+
+ @Inject
+ public JSoupXssFilter() {
+ none = new Cleaner(Whitelist.none());
+ relaxed = new Cleaner(getRelaxedWhiteList());
+ }
+
+ @Override
+ public String none(String input) {
+ return clean(input, none);
+ }
+
+ @Override
+ public String relaxed(String input) {
+ return clean(input, relaxed);
+ }
+
+ protected String clean(String input, Cleaner cleaner) {
+ Document unsafe = Jsoup.parse(input);
+ Document safe = cleaner.clean(unsafe);
+ return safe.body().html();
+ }
+
+ /**
+ * Builds & returns a loose HTML whitelist similar to Github.
+ *
+ * https://github.com/github/markup/tree/master#html-sanitization
+ * @return a loose HTML whitelist
+ */
+ protected Whitelist getRelaxedWhiteList() {
+ return new Whitelist()
+ .addTags(
+ "a", "b", "blockquote", "br", "caption", "cite", "code", "col",
+ "colgroup", "dd", "del", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", "hr",
+ "i", "img", "ins", "kbd", "li", "ol", "p", "pre", "q", "samp", "small", "strike", "strong",
+ "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "tt", "u",
+ "ul", "var")
+
+ .addAttributes("a", "href", "title")
+ .addAttributes("blockquote", "cite")
+ .addAttributes("col", "span", "width")
+ .addAttributes("colgroup", "span", "width")
+ .addAttributes("img", "align", "alt", "height", "src", "title", "width")
+ .addAttributes("ol", "start", "type")
+ .addAttributes("q", "cite")
+ .addAttributes("table", "summary", "width")
+ .addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width")
+ .addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width")
+ .addAttributes("ul", "type")
+
+ .addEnforcedAttribute("a", "rel", "nofollow")
+ ;
+ }
+
+}
diff --git a/src/main/java/com/gitblit/utils/XssFilter.java b/src/main/java/com/gitblit/utils/XssFilter.java
new file mode 100644
index 00000000..20b51057
--- /dev/null
+++ b/src/main/java/com/gitblit/utils/XssFilter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.utils;
+
+/**
+ * Defines the contract for an XSS filter implementation.
+ *
+ * @author James Moger
+ *
+ */
+public interface XssFilter {
+
+ /**
+ * Returns a filtered version of the input value that contains no html
+ * elements.
+ *
+ * @param input
+ * @return a plain text value
+ */
+ String none(String input);
+
+ /**
+ * Returns a filtered version of the input that contains structural html
+ * elements.
+ *
+ * @param input
+ * @return a filtered html value
+ */
+ String relaxed(String input);
+
+ /**
+ * A NOOP XSS filter.
+ *
+ * @author James Moger
+ *
+ */
+ public class AllowXssFilter implements XssFilter {
+
+ @Override
+ public String none(String input) {
+ return input;
+ }
+
+ @Override
+ public String relaxed(String input) {
+ return input;
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index 036a05a5..922e2045 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -47,6 +47,7 @@ import com.gitblit.manager.IServicesManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.tickets.ITicketService;
import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.utils.XssFilter;
import com.gitblit.wicket.pages.ActivityPage;
import com.gitblit.wicket.pages.BlamePage;
import com.gitblit.wicket.pages.BlobDiffPage;
@@ -109,6 +110,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
private final IStoredSettings settings;
+ private final XssFilter xssFilter;
+
private final IRuntimeManager runtimeManager;
private final IPluginManager pluginManager;
@@ -148,6 +151,7 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
this.publicKeyManagerProvider = publicKeyManagerProvider;
this.ticketServiceProvider = ticketServiceProvider;
this.settings = runtimeManager.getSettings();
+ this.xssFilter = runtimeManager.getXssFilter();
this.runtimeManager = runtimeManager;
this.pluginManager = pluginManager;
this.notificationManager = notificationManager;
@@ -265,7 +269,7 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
if (!settings.getBoolean(Keys.web.mountParameters, true)) {
parameters = new String[] {};
}
- mount(new GitblitParamUrlCodingStrategy(settings, location, clazz, parameters));
+ mount(new GitblitParamUrlCodingStrategy(settings, xssFilter, location, clazz, parameters));
// map the mount point to the cache control definition
if (clazz.isAnnotationPresent(CacheControl.class)) {
@@ -322,6 +326,14 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp {
}
/* (non-Javadoc)
+ * @see com.gitblit.wicket.Webapp#xssFilter()
+ */
+ @Override
+ public XssFilter xssFilter() {
+ return xssFilter;
+ }
+
+ /* (non-Javadoc)
* @see com.gitblit.wicket.Webapp#isDebugMode()
*/
@Override
diff --git a/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java b/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java
index c6583946..536f88f4 100644
--- a/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java
+++ b/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java
@@ -1,189 +1,221 @@
-/*
- * Copyright 2011 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit.wicket;
-
-import java.text.MessageFormat;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.wicket.IRequestTarget;
-import org.apache.wicket.Page;
-import org.apache.wicket.request.RequestParameters;
-import org.apache.wicket.request.target.coding.MixedParamUrlCodingStrategy;
-import org.apache.wicket.util.string.AppendingStringBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
-
-/**
- * Simple subclass of mixed parameter url coding strategy that works around the
- * encoded forward-slash issue that is present in some servlet containers.
- *
- * https://issues.apache.org/jira/browse/WICKET-1303
- * http://tomcat.apache.org/security-6.html
- *
- * @author James Moger
- *
- */
-public class GitblitParamUrlCodingStrategy extends MixedParamUrlCodingStrategy {
-
- private final String[] parameterNames;
-
- private Logger logger = LoggerFactory.getLogger(GitblitParamUrlCodingStrategy.class);
-
- private IStoredSettings settings;
-
- /**
- * Construct.
- *
- * @param <C>
- * @param mountPath
- * mount path (not empty)
- * @param bookmarkablePageClass
- * class of mounted page (not null)
- * @param parameterNames
- * the parameter names (not null)
- */
- public <C extends Page> GitblitParamUrlCodingStrategy(
- IStoredSettings settings,
- String mountPath,
- Class<C> bookmarkablePageClass, String[] parameterNames) {
-
- super(mountPath, bookmarkablePageClass, parameterNames);
- this.parameterNames = parameterNames;
- this.settings = settings;
- }
-
- /**
- * Url encodes a string that is mean for a URL path (e.g., between slashes)
- *
- * @param string
- * string to be encoded
- * @return encoded string
- */
- @Override
- protected String urlEncodePathComponent(String string) {
- char altChar = settings.getChar(Keys.web.forwardSlashCharacter, '/');
- if (altChar != '/') {
- string = string.replace('/', altChar);
- }
- return super.urlEncodePathComponent(string);
- }
-
- /**
- * Returns a decoded value of the given value (taken from a URL path
- * section)
- *
- * @param value
- * @return Decodes the value
- */
- @Override
- protected String urlDecodePathComponent(String value) {
- char altChar = settings.getChar(Keys.web.forwardSlashCharacter, '/');
- if (altChar != '/') {
- value = value.replace(altChar, '/');
- }
- return super.urlDecodePathComponent(value);
- }
-
- /**
- * Gets the decoded request target.
- *
- * @param requestParameters
- * the request parameters
- * @return the decoded request target
- */
- @Override
- public IRequestTarget decode(RequestParameters requestParameters) {
- final String parametersFragment = requestParameters.getPath().substring(
- getMountPath().length());
- logger.debug(MessageFormat
- .format("REQ: {0} PARAMS {1}", getMountPath(), parametersFragment));
-
- return super.decode(requestParameters);
- }
-
- /**
- * @see org.apache.wicket.request.target.coding.AbstractRequestTargetUrlCodingStrategy#appendParameters(org.apache.wicket.util.string.AppendingStringBuffer,
- * java.util.Map)
- */
- @Override
- protected void appendParameters(AppendingStringBuffer url, Map<String, ?> parameters)
- {
- if (!url.endsWith("/"))
- {
- url.append("/");
- }
-
- Set<String> parameterNamesToAdd = new HashSet<String>(parameters.keySet());
-
- // Find index of last specified parameter
- boolean foundParameter = false;
- int lastSpecifiedParameter = parameterNames.length;
- while (lastSpecifiedParameter != 0 && !foundParameter)
- {
- foundParameter = parameters.containsKey(parameterNames[--lastSpecifiedParameter]);
- }
-
- if (foundParameter)
- {
- for (int i = 0; i <= lastSpecifiedParameter; i++)
- {
- String parameterName = parameterNames[i];
- final Object param = parameters.get(parameterName);
- String value = param instanceof String[] ? ((String[])param)[0] : ((param == null)
- ? null : param.toString());
- if (value == null)
- {
- value = "";
- }
- if (!url.endsWith("/"))
- {
- url.append("/");
- }
- url.append(urlEncodePathComponent(value));
- parameterNamesToAdd.remove(parameterName);
- }
- }
-
- if (!parameterNamesToAdd.isEmpty())
- {
- boolean first = true;
- for (String parameterName : parameterNamesToAdd)
- {
- final Object param = parameters.get(parameterName);
- if (param instanceof String[]) {
- String [] values = (String[]) param;
- for (String value : values) {
- url.append(first ? '?' : '&');
- url.append(urlEncodeQueryComponent(parameterName)).append("=").append(
- urlEncodeQueryComponent(value));
- first = false;
- }
- } else {
- url.append(first ? '?' : '&');
- String value = String.valueOf(param);
- url.append(urlEncodeQueryComponent(parameterName)).append("=").append(
- urlEncodeQueryComponent(value));
- }
- first = false;
- }
- }
- }
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.Page;
+import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
+import org.apache.wicket.request.RequestParameters;
+import org.apache.wicket.request.target.coding.MixedParamUrlCodingStrategy;
+import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.utils.XssFilter;
+
+/**
+ * Simple subclass of mixed parameter url coding strategy that works around the
+ * encoded forward-slash issue that is present in some servlet containers.
+ *
+ * https://issues.apache.org/jira/browse/WICKET-1303
+ * http://tomcat.apache.org/security-6.html
+ *
+ * @author James Moger
+ *
+ */
+public class GitblitParamUrlCodingStrategy extends MixedParamUrlCodingStrategy {
+
+ private final String[] parameterNames;
+
+ private Logger logger = LoggerFactory.getLogger(GitblitParamUrlCodingStrategy.class);
+
+ private IStoredSettings settings;
+
+ private XssFilter xssFilter;
+
+ /**
+ * Construct.
+ *
+ * @param <C>
+ * @param mountPath
+ * mount path (not empty)
+ * @param bookmarkablePageClass
+ * class of mounted page (not null)
+ * @param parameterNames
+ * the parameter names (not null)
+ */
+ public <C extends Page> GitblitParamUrlCodingStrategy(
+ IStoredSettings settings,
+ XssFilter xssFilter,
+ String mountPath,
+ Class<C> bookmarkablePageClass, String[] parameterNames) {
+
+ super(mountPath, bookmarkablePageClass, parameterNames);
+ this.parameterNames = parameterNames;
+ this.settings = settings;
+ this.xssFilter = xssFilter;
+ }
+
+ /**
+ * Url encodes a string that is mean for a URL path (e.g., between slashes)
+ *
+ * @param string
+ * string to be encoded
+ * @return encoded string
+ */
+ @Override
+ protected String urlEncodePathComponent(String string) {
+ char altChar = settings.getChar(Keys.web.forwardSlashCharacter, '/');
+ if (altChar != '/') {
+ string = string.replace('/', altChar);
+ }
+ return super.urlEncodePathComponent(string);
+ }
+
+ /**
+ * Returns a decoded value of the given value (taken from a URL path
+ * section)
+ *
+ * @param value
+ * @return Decodes the value
+ */
+ @Override
+ protected String urlDecodePathComponent(String value) {
+ char altChar = settings.getChar(Keys.web.forwardSlashCharacter, '/');
+ if (altChar != '/') {
+ value = value.replace(altChar, '/');
+ }
+ return super.urlDecodePathComponent(value);
+ }
+
+ /**
+ * Gets the decoded request target.
+ *
+ * @param requestParameters
+ * the request parameters
+ * @return the decoded request target
+ */
+ @Override
+ public IRequestTarget decode(RequestParameters requestParameters) {
+ Map<String, Object> parameterMap = (Map<String, Object>) requestParameters.getParameters();
+ for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
+ String parameter = entry.getKey();
+ if (parameter.startsWith(WebRequestCodingStrategy.NAME_SPACE)) {
+ // ignore Wicket parameters
+ continue;
+ }
+
+ // sanitize Gitblit request parameters
+ Object o = entry.getValue();
+ if (o instanceof String) {
+ String value = o.toString();
+ String safeValue = xssFilter.none(value);
+ if (!value.equals(safeValue)) {
+ logger.warn("XSS filter triggered on {} URL parameter: {}={}",
+ getMountPath(), parameter, value);
+ parameterMap.put(parameter, safeValue);
+ }
+ } else if (o instanceof String[]) {
+ String[] values = (String[]) o;
+ for (int i = 0; i < values.length; i++) {
+ String value = values[i].toString();
+ String safeValue = xssFilter.none(value);
+ if (!value.equals(safeValue)) {
+ logger.warn("XSS filter triggered on {} URL parameter: {}={}",
+ getMountPath(), parameter, value);
+ values[i] = safeValue;
+ }
+ }
+ }
+ }
+
+ return super.decode(requestParameters);
+ }
+
+ /**
+ * @see org.apache.wicket.request.target.coding.AbstractRequestTargetUrlCodingStrategy#appendParameters(org.apache.wicket.util.string.AppendingStringBuffer,
+ * java.util.Map)
+ */
+ @Override
+ protected void appendParameters(AppendingStringBuffer url, Map<String, ?> parameters)
+ {
+ if (!url.endsWith("/"))
+ {
+ url.append("/");
+ }
+
+ Set<String> parameterNamesToAdd = new HashSet<String>(parameters.keySet());
+
+ // Find index of last specified parameter
+ boolean foundParameter = false;
+ int lastSpecifiedParameter = parameterNames.length;
+ while (lastSpecifiedParameter != 0 && !foundParameter)
+ {
+ foundParameter = parameters.containsKey(parameterNames[--lastSpecifiedParameter]);
+ }
+
+ if (foundParameter)
+ {
+ for (int i = 0; i <= lastSpecifiedParameter; i++)
+ {
+ String parameterName = parameterNames[i];
+ final Object param = parameters.get(parameterName);
+ String value = param instanceof String[] ? ((String[])param)[0] : ((param == null)
+ ? null : param.toString());
+ if (value == null)
+ {
+ value = "";
+ }
+ if (!url.endsWith("/"))
+ {
+ url.append("/");
+ }
+ url.append(urlEncodePathComponent(value));
+ parameterNamesToAdd.remove(parameterName);
+ }
+ }
+
+ if (!parameterNamesToAdd.isEmpty())
+ {
+ boolean first = true;
+ for (String parameterName : parameterNamesToAdd)
+ {
+ final Object param = parameters.get(parameterName);
+ if (param instanceof String[]) {
+ String [] values = (String[]) param;
+ for (String value : values) {
+ url.append(first ? '?' : '&');
+ url.append(urlEncodeQueryComponent(parameterName)).append("=").append(
+ urlEncodeQueryComponent(value));
+ first = false;
+ }
+ } else {
+ url.append(first ? '?' : '&');
+ String value = String.valueOf(param);
+ url.append(urlEncodeQueryComponent(parameterName)).append("=").append(
+ urlEncodeQueryComponent(value));
+ }
+ first = false;
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
index 7013097c..3041c5da 100644
--- a/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
+++ b/src/main/java/com/gitblit/wicket/GitblitWicketApp.java
@@ -18,6 +18,7 @@ import com.gitblit.manager.IServicesManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.tickets.ITicketService;
import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.utils.XssFilter;
public interface GitblitWicketApp {
@@ -31,6 +32,8 @@ public interface GitblitWicketApp {
public abstract IStoredSettings settings();
+ public abstract XssFilter xssFilter();
+
/**
* Is Gitblit running in debug mode?
*
diff --git a/src/main/java/com/gitblit/wicket/MarkupProcessor.java b/src/main/java/com/gitblit/wicket/MarkupProcessor.java
index e7681f2c..b2032049 100644
--- a/src/main/java/com/gitblit/wicket/MarkupProcessor.java
+++ b/src/main/java/com/gitblit/wicket/MarkupProcessor.java
@@ -1,457 +1,473 @@
-/*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit.wicket;
-
-import static org.pegdown.FastEncoder.encode;
-
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.wicket.Page;
-import org.apache.wicket.RequestCycle;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.mylyn.wikitext.confluence.core.ConfluenceLanguage;
-import org.eclipse.mylyn.wikitext.core.parser.Attributes;
-import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
-import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
-import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
-import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
-import org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
-import org.eclipse.mylyn.wikitext.tracwiki.core.TracWikiLanguage;
-import org.eclipse.mylyn.wikitext.twiki.core.TWikiLanguage;
-import org.pegdown.DefaultVerbatimSerializer;
-import org.pegdown.LinkRenderer;
-import org.pegdown.ToHtmlSerializer;
-import org.pegdown.VerbatimSerializer;
-import org.pegdown.ast.ExpImageNode;
-import org.pegdown.ast.RefImageNode;
-import org.pegdown.ast.WikiLinkNode;
-import org.pegdown.plugins.ToHtmlSerializerPlugin;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
-import com.gitblit.models.PathModel;
-import com.gitblit.servlet.RawServlet;
-import com.gitblit.utils.JGitUtils;
-import com.gitblit.utils.MarkdownUtils;
-import com.gitblit.utils.StringUtils;
-import com.gitblit.wicket.pages.DocPage;
-import com.google.common.base.Joiner;
-
-/**
- * Processes markup content and generates html with repository-relative page and
- * image linking.
- *
- * @author James Moger
- *
- */
-public class MarkupProcessor {
-
- public enum MarkupSyntax {
- PLAIN, MARKDOWN, TWIKI, TRACWIKI, TEXTILE, MEDIAWIKI, CONFLUENCE
- }
-
- private Logger logger = LoggerFactory.getLogger(getClass());
-
- private final IStoredSettings settings;
-
- public MarkupProcessor(IStoredSettings settings) {
- this.settings = settings;
- }
-
- public List<String> getMarkupExtensions() {
- List<String> list = new ArrayList<String>();
- list.addAll(settings.getStrings(Keys.web.confluenceExtensions));
- list.addAll(settings.getStrings(Keys.web.markdownExtensions));
- list.addAll(settings.getStrings(Keys.web.mediawikiExtensions));
- list.addAll(settings.getStrings(Keys.web.textileExtensions));
- list.addAll(settings.getStrings(Keys.web.tracwikiExtensions));
- list.addAll(settings.getStrings(Keys.web.twikiExtensions));
- return list;
- }
-
- public List<String> getAllExtensions() {
- List<String> list = getMarkupExtensions();
- list.add("txt");
- list.add("TXT");
- return list;
- }
-
- private List<String> getRoots() {
- return settings.getStrings(Keys.web.documents);
- }
-
- private String [] getEncodings() {
- return settings.getStrings(Keys.web.blobEncodings).toArray(new String[0]);
- }
-
- private MarkupSyntax determineSyntax(String documentPath) {
- String ext = StringUtils.getFileExtension(documentPath).toLowerCase();
- if (StringUtils.isEmpty(ext)) {
- return MarkupSyntax.PLAIN;
- }
-
- if (settings.getStrings(Keys.web.confluenceExtensions).contains(ext)) {
- return MarkupSyntax.CONFLUENCE;
- } else if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
- return MarkupSyntax.MARKDOWN;
- } else if (settings.getStrings(Keys.web.mediawikiExtensions).contains(ext)) {
- return MarkupSyntax.MEDIAWIKI;
- } else if (settings.getStrings(Keys.web.textileExtensions).contains(ext)) {
- return MarkupSyntax.TEXTILE;
- } else if (settings.getStrings(Keys.web.tracwikiExtensions).contains(ext)) {
- return MarkupSyntax.TRACWIKI;
- } else if (settings.getStrings(Keys.web.twikiExtensions).contains(ext)) {
- return MarkupSyntax.TWIKI;
- }
-
- return MarkupSyntax.PLAIN;
- }
-
- public boolean hasRootDocs(Repository r) {
- List<String> roots = getRoots();
- List<String> extensions = getAllExtensions();
- List<PathModel> paths = JGitUtils.getFilesInPath(r, null, null);
- for (PathModel path : paths) {
- if (!path.isTree()) {
- String ext = StringUtils.getFileExtension(path.name).toLowerCase();
- String name = StringUtils.stripFileExtension(path.name).toLowerCase();
-
- if (roots.contains(name)) {
- if (StringUtils.isEmpty(ext) || extensions.contains(ext)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- public List<MarkupDocument> getRootDocs(Repository r, String repositoryName, String commitId) {
- List<String> roots = getRoots();
- List<MarkupDocument> list = getDocs(r, repositoryName, commitId, roots);
- return list;
- }
-
- public MarkupDocument getReadme(Repository r, String repositoryName, String commitId) {
- List<MarkupDocument> list = getDocs(r, repositoryName, commitId, Arrays.asList("readme"));
- if (list.isEmpty()) {
- return null;
- }
- return list.get(0);
- }
-
- private List<MarkupDocument> getDocs(Repository r, String repositoryName, String commitId, List<String> names) {
- List<String> extensions = getAllExtensions();
- String [] encodings = getEncodings();
- Map<String, MarkupDocument> map = new HashMap<String, MarkupDocument>();
- RevCommit commit = JGitUtils.getCommit(r, commitId);
- List<PathModel> paths = JGitUtils.getFilesInPath(r, null, commit);
- for (PathModel path : paths) {
- if (!path.isTree()) {
- String ext = StringUtils.getFileExtension(path.name).toLowerCase();
- String name = StringUtils.stripFileExtension(path.name).toLowerCase();
-
- if (names.contains(name)) {
- if (StringUtils.isEmpty(ext) || extensions.contains(ext)) {
- String markup = JGitUtils.getStringContent(r, commit.getTree(), path.name, encodings);
- MarkupDocument doc = parse(repositoryName, commitId, path.name, markup);
- map.put(name, doc);
- }
- }
- }
- }
- // return document list in requested order
- List<MarkupDocument> list = new ArrayList<MarkupDocument>();
- for (String name : names) {
- if (map.containsKey(name)) {
- list.add(map.get(name));
- }
- }
- return list;
- }
-
- public MarkupDocument parse(String repositoryName, String commitId, String documentPath, String markupText) {
- final MarkupSyntax syntax = determineSyntax(documentPath);
- final MarkupDocument doc = new MarkupDocument(documentPath, markupText, syntax);
-
- if (markupText != null) {
- try {
- switch (syntax){
- case CONFLUENCE:
- parse(doc, repositoryName, commitId, new ConfluenceLanguage());
- break;
- case MARKDOWN:
- parse(doc, repositoryName, commitId);
- break;
- case MEDIAWIKI:
- parse(doc, repositoryName, commitId, new MediaWikiLanguage());
- break;
- case TEXTILE:
- parse(doc, repositoryName, commitId, new TextileLanguage());
- break;
- case TRACWIKI:
- parse(doc, repositoryName, commitId, new TracWikiLanguage());
- break;
- case TWIKI:
- parse(doc, repositoryName, commitId, new TWikiLanguage());
- break;
- default:
- doc.html = MarkdownUtils.transformPlainText(markupText);
- break;
- }
- } catch (Exception e) {
- logger.error("failed to transform " + syntax, e);
- }
- }
-
- if (doc.html == null) {
- // failed to transform markup
- if (markupText == null) {
- markupText = String.format("Document <b>%1$s</b> not found in <em>%2$s</em>", documentPath, repositoryName);
- }
- markupText = MessageFormat.format("<div class=\"alert alert-error\"><strong>{0}:</strong> {1}</div>{2}", "Error", "failed to parse markup", markupText);
- doc.html = StringUtils.breakLinesForHtml(markupText);
- }
-
- return doc;
- }
-
- /**
- * Parses the markup using the specified markup language
- *
- * @param doc
- * @param repositoryName
- * @param commitId
- * @param lang
- */
- private void parse(final MarkupDocument doc, final String repositoryName, final String commitId, MarkupLanguage lang) {
- StringWriter writer = new StringWriter();
- HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer) {
-
- @Override
- public void image(Attributes attributes, String imagePath) {
- String url;
- if (imagePath.indexOf("://") == -1) {
- // relative image
- String path = doc.getRelativePath(imagePath);
- String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
- url = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
- } else {
- // absolute image
- url = imagePath;
- }
- super.image(attributes, url);
- }
-
- @Override
- public void link(Attributes attributes, String hrefOrHashName, String text) {
- String url;
- if (hrefOrHashName.charAt(0) != '#') {
- if (hrefOrHashName.indexOf("://") == -1) {
- // relative link
- String path = doc.getRelativePath(hrefOrHashName);
- url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
- } else {
- // absolute link
- url = hrefOrHashName;
- }
- } else {
- // page-relative hash link
- url = hrefOrHashName;
- }
- super.link(attributes, url, text);
- }
- };
-
- // avoid the <html> and <body> tags
- builder.setEmitAsDocument(false);
-
- MarkupParser parser = new MarkupParser(lang);
- parser.setBuilder(builder);
- parser.parse(doc.markup);
- doc.html = writer.toString();
- }
-
- /**
- * Parses the document as Markdown using Pegdown.
- *
- * @param doc
- * @param repositoryName
- * @param commitId
- */
- private void parse(final MarkupDocument doc, final String repositoryName, final String commitId) {
- LinkRenderer renderer = new LinkRenderer() {
-
- @Override
- public Rendering render(ExpImageNode node, String text) {
- if (node.url.indexOf("://") == -1) {
- // repository-relative image link
- String path = doc.getRelativePath(node.url);
- String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
- String url = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
- return new Rendering(url, text);
- }
- // absolute image link
- return new Rendering(node.url, text);
- }
-
- @Override
- public Rendering render(RefImageNode node, String url, String title, String alt) {
- Rendering rendering;
- if (url.indexOf("://") == -1) {
- // repository-relative image link
- String path = doc.getRelativePath(url);
- String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
- String wurl = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
- rendering = new Rendering(wurl, alt);
- } else {
- // absolute image link
- rendering = new Rendering(url, alt);
- }
- return StringUtils.isEmpty(title) ? rendering : rendering.withAttribute("title", encode(title));
- }
-
- @Override
- public Rendering render(WikiLinkNode node) {
- String path = doc.getRelativePath(node.getText());
- String name = getDocumentName(path);
- String url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
- return new Rendering(url, name);
- }
- };
- doc.html = MarkdownUtils.transformMarkdown(doc.markup, renderer);
- }
-
- private String getWicketUrl(Class<? extends Page> pageClass, final String repositoryName, final String commitId, final String document) {
- String fsc = settings.getString(Keys.web.forwardSlashCharacter, "/");
- String encodedPath = document.replace(' ', '-');
- try {
- encodedPath = URLEncoder.encode(encodedPath, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- logger.error(null, e);
- }
- encodedPath = encodedPath.replace("/", fsc).replace("%2F", fsc);
-
- String url = RequestCycle.get().urlFor(pageClass, WicketUtils.newPathParameter(repositoryName, commitId, encodedPath)).toString();
- return url;
- }
-
- private String getDocumentName(final String document) {
- // extract document name
- String name = StringUtils.stripFileExtension(document);
- name = name.replace('_', ' ');
- if (name.indexOf('/') > -1) {
- name = name.substring(name.lastIndexOf('/') + 1);
- }
- return name;
- }
-
- public static class MarkupDocument implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- public final String documentPath;
- public final String markup;
- public final MarkupSyntax syntax;
- public String html;
-
- MarkupDocument(String documentPath, String markup, MarkupSyntax syntax) {
- this.documentPath = documentPath;
- this.markup = markup;
- this.syntax = syntax;
- }
-
- String getCurrentPath() {
- String basePath = "";
- if (documentPath.indexOf('/') > -1) {
- basePath = documentPath.substring(0, documentPath.lastIndexOf('/') + 1);
- if (basePath.charAt(0) == '/') {
- return basePath.substring(1);
- }
- }
- return basePath;
- }
-
- String getRelativePath(String ref) {
- if (ref.charAt(0) == '/') {
- // absolute path in repository
- return ref.substring(1);
- } else {
- // resolve relative repository path
- String cp = getCurrentPath();
- if (StringUtils.isEmpty(cp)) {
- return ref;
- }
- // this is a simple relative path resolver
- List<String> currPathStrings = new ArrayList<String>(Arrays.asList(cp.split("/")));
- String file = ref;
- while (file.startsWith("../")) {
- // strip ../ from the file reference
- // drop the last path element
- file = file.substring(3);
- currPathStrings.remove(currPathStrings.size() - 1);
- }
- currPathStrings.add(file);
- String path = Joiner.on("/").join(currPathStrings);
- return path;
- }
- }
- }
-
- /**
- * This class implements a workaround for a bug reported in issue-379.
- * The bug was introduced by my own pegdown pull request #115.
- *
- * @author James Moger
- *
- */
- public static class WorkaroundHtmlSerializer extends ToHtmlSerializer {
-
- public WorkaroundHtmlSerializer(final LinkRenderer linkRenderer) {
- super(linkRenderer,
- Collections.<String, VerbatimSerializer>singletonMap(VerbatimSerializer.DEFAULT, DefaultVerbatimSerializer.INSTANCE),
- Collections.<ToHtmlSerializerPlugin>emptyList());
- }
- private void printAttribute(String name, String value) {
- printer.print(' ').print(name).print('=').print('"').print(value).print('"');
- }
-
- /* Reimplement print image tag to eliminate a trailing double-quote */
- @Override
- protected void printImageTag(LinkRenderer.Rendering rendering) {
- printer.print("<img");
- printAttribute("src", rendering.href);
- printAttribute("alt", rendering.text);
- for (LinkRenderer.Attribute attr : rendering.attributes) {
- printAttribute(attr.name, attr.value);
- }
- printer.print("/>");
- }
- }
-}
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket;
+
+import static org.pegdown.FastEncoder.encode;
+
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.RequestCycle;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.mylyn.wikitext.confluence.core.ConfluenceLanguage;
+import org.eclipse.mylyn.wikitext.core.parser.Attributes;
+import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
+import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
+import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
+import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
+import org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
+import org.eclipse.mylyn.wikitext.tracwiki.core.TracWikiLanguage;
+import org.eclipse.mylyn.wikitext.twiki.core.TWikiLanguage;
+import org.pegdown.DefaultVerbatimSerializer;
+import org.pegdown.LinkRenderer;
+import org.pegdown.ToHtmlSerializer;
+import org.pegdown.VerbatimSerializer;
+import org.pegdown.ast.ExpImageNode;
+import org.pegdown.ast.RefImageNode;
+import org.pegdown.ast.WikiLinkNode;
+import org.pegdown.plugins.ToHtmlSerializerPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.models.PathModel;
+import com.gitblit.servlet.RawServlet;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.wicket.pages.DocPage;
+import com.google.common.base.Joiner;
+
+/**
+ * Processes markup content and generates html with repository-relative page and
+ * image linking.
+ *
+ * @author James Moger
+ *
+ */
+public class MarkupProcessor {
+
+ public enum MarkupSyntax {
+ PLAIN, MARKDOWN, TWIKI, TRACWIKI, TEXTILE, MEDIAWIKI, CONFLUENCE
+ }
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final IStoredSettings settings;
+
+ private final XssFilter xssFilter;
+
+ public static List<String> getMarkupExtensions(IStoredSettings settings) {
+ List<String> list = new ArrayList<String>();
+ list.addAll(settings.getStrings(Keys.web.confluenceExtensions));
+ list.addAll(settings.getStrings(Keys.web.markdownExtensions));
+ list.addAll(settings.getStrings(Keys.web.mediawikiExtensions));
+ list.addAll(settings.getStrings(Keys.web.textileExtensions));
+ list.addAll(settings.getStrings(Keys.web.tracwikiExtensions));
+ list.addAll(settings.getStrings(Keys.web.twikiExtensions));
+ return list;
+ }
+
+ public MarkupProcessor(IStoredSettings settings, XssFilter xssFilter) {
+ this.settings = settings;
+ this.xssFilter = xssFilter;
+ }
+
+ public List<String> getMarkupExtensions() {
+ return getMarkupExtensions(settings);
+ }
+
+ public List<String> getAllExtensions() {
+ List<String> list = getMarkupExtensions(settings);
+ list.add("txt");
+ list.add("TXT");
+ return list;
+ }
+
+ private List<String> getRoots() {
+ return settings.getStrings(Keys.web.documents);
+ }
+
+ private String [] getEncodings() {
+ return settings.getStrings(Keys.web.blobEncodings).toArray(new String[0]);
+ }
+
+ private MarkupSyntax determineSyntax(String documentPath) {
+ String ext = StringUtils.getFileExtension(documentPath).toLowerCase();
+ if (StringUtils.isEmpty(ext)) {
+ return MarkupSyntax.PLAIN;
+ }
+
+ if (settings.getStrings(Keys.web.confluenceExtensions).contains(ext)) {
+ return MarkupSyntax.CONFLUENCE;
+ } else if (settings.getStrings(Keys.web.markdownExtensions).contains(ext)) {
+ return MarkupSyntax.MARKDOWN;
+ } else if (settings.getStrings(Keys.web.mediawikiExtensions).contains(ext)) {
+ return MarkupSyntax.MEDIAWIKI;
+ } else if (settings.getStrings(Keys.web.textileExtensions).contains(ext)) {
+ return MarkupSyntax.TEXTILE;
+ } else if (settings.getStrings(Keys.web.tracwikiExtensions).contains(ext)) {
+ return MarkupSyntax.TRACWIKI;
+ } else if (settings.getStrings(Keys.web.twikiExtensions).contains(ext)) {
+ return MarkupSyntax.TWIKI;
+ }
+
+ return MarkupSyntax.PLAIN;
+ }
+
+ public boolean hasRootDocs(Repository r) {
+ List<String> roots = getRoots();
+ List<String> extensions = getAllExtensions();
+ List<PathModel> paths = JGitUtils.getFilesInPath(r, null, null);
+ for (PathModel path : paths) {
+ if (!path.isTree()) {
+ String ext = StringUtils.getFileExtension(path.name).toLowerCase();
+ String name = StringUtils.stripFileExtension(path.name).toLowerCase();
+
+ if (roots.contains(name)) {
+ if (StringUtils.isEmpty(ext) || extensions.contains(ext)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public List<MarkupDocument> getRootDocs(Repository r, String repositoryName, String commitId) {
+ List<String> roots = getRoots();
+ List<MarkupDocument> list = getDocs(r, repositoryName, commitId, roots);
+ return list;
+ }
+
+ public MarkupDocument getReadme(Repository r, String repositoryName, String commitId) {
+ List<MarkupDocument> list = getDocs(r, repositoryName, commitId, Arrays.asList("readme"));
+ if (list.isEmpty()) {
+ return null;
+ }
+ return list.get(0);
+ }
+
+ private List<MarkupDocument> getDocs(Repository r, String repositoryName, String commitId, List<String> names) {
+ List<String> extensions = getAllExtensions();
+ String [] encodings = getEncodings();
+ Map<String, MarkupDocument> map = new HashMap<String, MarkupDocument>();
+ RevCommit commit = JGitUtils.getCommit(r, commitId);
+ List<PathModel> paths = JGitUtils.getFilesInPath(r, null, commit);
+ for (PathModel path : paths) {
+ if (!path.isTree()) {
+ String ext = StringUtils.getFileExtension(path.name).toLowerCase();
+ String name = StringUtils.stripFileExtension(path.name).toLowerCase();
+
+ if (names.contains(name)) {
+ if (StringUtils.isEmpty(ext) || extensions.contains(ext)) {
+ String markup = JGitUtils.getStringContent(r, commit.getTree(), path.name, encodings);
+ MarkupDocument doc = parse(repositoryName, commitId, path.name, markup);
+ map.put(name, doc);
+ }
+ }
+ }
+ }
+ // return document list in requested order
+ List<MarkupDocument> list = new ArrayList<MarkupDocument>();
+ for (String name : names) {
+ if (map.containsKey(name)) {
+ list.add(map.get(name));
+ }
+ }
+ return list;
+ }
+
+ public MarkupDocument parse(String repositoryName, String commitId, String documentPath, String markupText) {
+ final MarkupSyntax syntax = determineSyntax(documentPath);
+ final MarkupDocument doc = new MarkupDocument(documentPath, markupText, syntax);
+
+ if (markupText != null) {
+ try {
+ switch (syntax){
+ case CONFLUENCE:
+ parse(doc, repositoryName, commitId, new ConfluenceLanguage());
+ break;
+ case MARKDOWN:
+ parse(doc, repositoryName, commitId);
+ break;
+ case MEDIAWIKI:
+ parse(doc, repositoryName, commitId, new MediaWikiLanguage());
+ break;
+ case TEXTILE:
+ parse(doc, repositoryName, commitId, new TextileLanguage());
+ break;
+ case TRACWIKI:
+ parse(doc, repositoryName, commitId, new TracWikiLanguage());
+ break;
+ case TWIKI:
+ parse(doc, repositoryName, commitId, new TWikiLanguage());
+ break;
+ default:
+ doc.html = MarkdownUtils.transformPlainText(markupText);
+ break;
+ }
+ } catch (Exception e) {
+ logger.error("failed to transform " + syntax, e);
+ }
+ }
+
+ if (doc.html == null) {
+ // failed to transform markup
+ if (markupText == null) {
+ markupText = String.format("Document <b>%1$s</b> not found in <em>%2$s</em>", documentPath, repositoryName);
+ }
+ markupText = MessageFormat.format("<div class=\"alert alert-error\"><strong>{0}:</strong> {1}</div>{2}", "Error", "failed to parse markup", markupText);
+ doc.html = StringUtils.breakLinesForHtml(markupText);
+ }
+
+ return doc;
+ }
+
+ /**
+ * Parses the markup using the specified markup language
+ *
+ * @param doc
+ * @param repositoryName
+ * @param commitId
+ * @param lang
+ */
+ private void parse(final MarkupDocument doc, final String repositoryName, final String commitId, MarkupLanguage lang) {
+ StringWriter writer = new StringWriter();
+ HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer) {
+
+ @Override
+ public void image(Attributes attributes, String imagePath) {
+ String url;
+ if (imagePath.indexOf("://") == -1) {
+ // relative image
+ String path = doc.getRelativePath(imagePath);
+ String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
+ url = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
+ } else {
+ // absolute image
+ url = imagePath;
+ }
+ super.image(attributes, url);
+ }
+
+ @Override
+ public void link(Attributes attributes, String hrefOrHashName, String text) {
+ String url;
+ if (hrefOrHashName.charAt(0) != '#') {
+ if (hrefOrHashName.indexOf("://") == -1) {
+ // relative link
+ String path = doc.getRelativePath(hrefOrHashName);
+ url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
+ } else {
+ // absolute link
+ url = hrefOrHashName;
+ }
+ } else {
+ // page-relative hash link
+ url = hrefOrHashName;
+ }
+ super.link(attributes, url, text);
+ }
+ };
+
+ // avoid the <html> and <body> tags
+ builder.setEmitAsDocument(false);
+
+ MarkupParser parser = new MarkupParser(lang);
+ parser.setBuilder(builder);
+ parser.parse(doc.markup);
+
+ final String content = writer.toString();
+ final String safeContent = xssFilter.relaxed(content);
+
+ doc.html = safeContent;
+ }
+
+ /**
+ * Parses the document as Markdown using Pegdown.
+ *
+ * @param doc
+ * @param repositoryName
+ * @param commitId
+ */
+ private void parse(final MarkupDocument doc, final String repositoryName, final String commitId) {
+ LinkRenderer renderer = new LinkRenderer() {
+
+ @Override
+ public Rendering render(ExpImageNode node, String text) {
+ if (node.url.indexOf("://") == -1) {
+ // repository-relative image link
+ String path = doc.getRelativePath(node.url);
+ String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
+ String url = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
+ return new Rendering(url, text);
+ }
+ // absolute image link
+ return new Rendering(node.url, text);
+ }
+
+ @Override
+ public Rendering render(RefImageNode node, String url, String title, String alt) {
+ Rendering rendering;
+ if (url.indexOf("://") == -1) {
+ // repository-relative image link
+ String path = doc.getRelativePath(url);
+ String contextUrl = RequestCycle.get().getRequest().getRelativePathPrefixToContextRoot();
+ String wurl = RawServlet.asLink(contextUrl, repositoryName, commitId, path);
+ rendering = new Rendering(wurl, alt);
+ } else {
+ // absolute image link
+ rendering = new Rendering(url, alt);
+ }
+ return StringUtils.isEmpty(title) ? rendering : rendering.withAttribute("title", encode(title));
+ }
+
+ @Override
+ public Rendering render(WikiLinkNode node) {
+ String path = doc.getRelativePath(node.getText());
+ String name = getDocumentName(path);
+ String url = getWicketUrl(DocPage.class, repositoryName, commitId, path);
+ return new Rendering(url, name);
+ }
+ };
+
+ final String content = MarkdownUtils.transformMarkdown(doc.markup, renderer);
+ final String safeContent = xssFilter.relaxed(content);
+
+ doc.html = safeContent;
+ }
+
+ private String getWicketUrl(Class<? extends Page> pageClass, final String repositoryName, final String commitId, final String document) {
+ String fsc = settings.getString(Keys.web.forwardSlashCharacter, "/");
+ String encodedPath = document.replace(' ', '-');
+ try {
+ encodedPath = URLEncoder.encode(encodedPath, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ logger.error(null, e);
+ }
+ encodedPath = encodedPath.replace("/", fsc).replace("%2F", fsc);
+
+ String url = RequestCycle.get().urlFor(pageClass, WicketUtils.newPathParameter(repositoryName, commitId, encodedPath)).toString();
+ return url;
+ }
+
+ private String getDocumentName(final String document) {
+ // extract document name
+ String name = StringUtils.stripFileExtension(document);
+ name = name.replace('_', ' ');
+ if (name.indexOf('/') > -1) {
+ name = name.substring(name.lastIndexOf('/') + 1);
+ }
+ return name;
+ }
+
+ public static class MarkupDocument implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String documentPath;
+ public final String markup;
+ public final MarkupSyntax syntax;
+ public String html;
+
+ MarkupDocument(String documentPath, String markup, MarkupSyntax syntax) {
+ this.documentPath = documentPath;
+ this.markup = markup;
+ this.syntax = syntax;
+ }
+
+ String getCurrentPath() {
+ String basePath = "";
+ if (documentPath.indexOf('/') > -1) {
+ basePath = documentPath.substring(0, documentPath.lastIndexOf('/') + 1);
+ if (basePath.charAt(0) == '/') {
+ return basePath.substring(1);
+ }
+ }
+ return basePath;
+ }
+
+ String getRelativePath(String ref) {
+ if (ref.charAt(0) == '/') {
+ // absolute path in repository
+ return ref.substring(1);
+ } else {
+ // resolve relative repository path
+ String cp = getCurrentPath();
+ if (StringUtils.isEmpty(cp)) {
+ return ref;
+ }
+ // this is a simple relative path resolver
+ List<String> currPathStrings = new ArrayList<String>(Arrays.asList(cp.split("/")));
+ String file = ref;
+ while (file.startsWith("../")) {
+ // strip ../ from the file reference
+ // drop the last path element
+ file = file.substring(3);
+ currPathStrings.remove(currPathStrings.size() - 1);
+ }
+ currPathStrings.add(file);
+ String path = Joiner.on("/").join(currPathStrings);
+ return path;
+ }
+ }
+ }
+
+ /**
+ * This class implements a workaround for a bug reported in issue-379.
+ * The bug was introduced by my own pegdown pull request #115.
+ *
+ * @author James Moger
+ *
+ */
+ public static class WorkaroundHtmlSerializer extends ToHtmlSerializer {
+
+ public WorkaroundHtmlSerializer(final LinkRenderer linkRenderer) {
+ super(linkRenderer,
+ Collections.<String, VerbatimSerializer>singletonMap(VerbatimSerializer.DEFAULT, DefaultVerbatimSerializer.INSTANCE),
+ Collections.<ToHtmlSerializerPlugin>emptyList());
+ }
+ private void printAttribute(String name, String value) {
+ printer.print(' ').print(name).print('=').print('"').print(value).print('"');
+ }
+
+ /* Reimplement print image tag to eliminate a trailing double-quote */
+ @Override
+ protected void printImageTag(LinkRenderer.Rendering rendering) {
+ printer.print("<img");
+ printAttribute("src", rendering.href);
+ printAttribute("alt", rendering.text);
+ for (LinkRenderer.Attribute attr : rendering.attributes) {
+ printAttribute(attr.name, attr.value);
+ }
+ printer.print("/>");
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/SafeTextModel.java b/src/main/java/com/gitblit/wicket/SafeTextModel.java
new file mode 100644
index 00000000..aef7e97a
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/SafeTextModel.java
@@ -0,0 +1,96 @@
+package com.gitblit.wicket;
+
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.lang.Objects;
+import org.parboiled.common.StringUtils;
+import org.slf4j.LoggerFactory;
+
+public class SafeTextModel implements IModel<String> {
+
+ private static final long serialVersionUID = 1L;
+
+ public enum Mode {
+ relaxed, none
+ }
+
+ private final Mode mode;
+
+ private String value;
+
+ public static SafeTextModel none() {
+ return new SafeTextModel(Mode.none);
+ }
+
+ public static SafeTextModel none(String value) {
+ return new SafeTextModel(Mode.none);
+ }
+
+ public static SafeTextModel relaxed() {
+ return new SafeTextModel(Mode.relaxed);
+ }
+
+ public static SafeTextModel relaxed(String value) {
+ return new SafeTextModel(Mode.relaxed);
+ }
+
+ public SafeTextModel(Mode mode) {
+ this.mode = mode;
+ }
+
+ public SafeTextModel(String value, Mode mode) {
+ this.value = value;
+ this.mode = mode;
+ }
+
+ @Override
+ public void detach() {
+ }
+
+ @Override
+ public String getObject() {
+ if (StringUtils.isEmpty(value)) {
+ return value;
+ }
+ String safeValue;
+ switch (mode) {
+ case none:
+ safeValue = GitBlitWebApp.get().xssFilter().none(value);
+ break;
+ default:
+ safeValue = GitBlitWebApp.get().xssFilter().relaxed(value);
+ break;
+ }
+ if (!value.equals(safeValue)) {
+ LoggerFactory.getLogger(getClass()).warn("XSS filter trigggered on suspicious form field value {}",
+ value);
+ }
+ return safeValue;
+ }
+
+ @Override
+ public void setObject(String input) {
+ this.value = input;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (!(obj instanceof Model<?>))
+ {
+ return false;
+ }
+ Model<?> that = (Model<?>)obj;
+ return Objects.equal(value, that.getObject());
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java
index 687f0105..d47390d4 100644
--- a/src/main/java/com/gitblit/wicket/WicketUtils.java
+++ b/src/main/java/com/gitblit/wicket/WicketUtils.java
@@ -42,6 +42,7 @@ import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import com.gitblit.Constants;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.FederationPullStatus;
+import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.models.FederationModel;
import com.gitblit.models.Metric;
@@ -186,9 +187,9 @@ public class WicketUtils {
return newImage(wicketId, "file_settings_16x16.png");
}
- MarkupProcessor processor = new MarkupProcessor(GitBlitWebApp.get().settings());
String ext = StringUtils.getFileExtension(filename).toLowerCase();
- if (processor.getMarkupExtensions().contains(ext)) {
+ IStoredSettings settings = GitBlitWebApp.get().settings();
+ if (MarkupProcessor.getMarkupExtensions(settings).contains(ext)) {
return newImage(wicketId, "file_world_16x16.png");
}
return newImage(wicketId, "file_16x16.png");
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.java b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
index 0938fcde..e84056b3 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
@@ -79,7 +79,7 @@ public class BlobPage extends RepositoryPage {
}
// see if we should redirect to the doc page
- MarkupProcessor processor = new MarkupProcessor(app().settings());
+ MarkupProcessor processor = new MarkupProcessor(app().settings(), app().xssFilter());
for (String ext : processor.getMarkupExtensions()) {
if (ext.equals(extension)) {
setResponsePage(DocPage.class, params);
diff --git a/src/main/java/com/gitblit/wicket/pages/DocPage.java b/src/main/java/com/gitblit/wicket/pages/DocPage.java
index c06d8065..567c6fbd 100644
--- a/src/main/java/com/gitblit/wicket/pages/DocPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/DocPage.java
@@ -43,7 +43,7 @@ public class DocPage extends RepositoryPage {
super(params);
final String path = WicketUtils.getPath(params).replace("%2f", "/").replace("%2F", "/");
- MarkupProcessor processor = new MarkupProcessor(app().settings());
+ MarkupProcessor processor = new MarkupProcessor(app().settings(), app().xssFilter());
Repository r = getRepository();
RevCommit commit = JGitUtils.getCommit(r, objectId);
diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.java b/src/main/java/com/gitblit/wicket/pages/DocsPage.java
index fc56ee07..a3d0f214 100644
--- a/src/main/java/com/gitblit/wicket/pages/DocsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.java
@@ -49,7 +49,7 @@ public class DocsPage extends RepositoryPage {
public DocsPage(PageParameters params) {
super(params);
- MarkupProcessor processor = new MarkupProcessor(app().settings());
+ MarkupProcessor processor = new MarkupProcessor(app().settings(), app().xssFilter());
Repository r = getRepository();
RevCommit head = JGitUtils.getCommit(r, null);
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
index 4a06e59e..bd2ec63c 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditTicketPage.java
@@ -50,6 +50,8 @@ import com.gitblit.tickets.TicketNotifier;
import com.gitblit.tickets.TicketResponsible;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.SafeTextModel;
+import com.gitblit.wicket.SafeTextModel.Mode;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.MarkdownTextArea;
@@ -110,8 +112,8 @@ public class EditTicketPage extends RepositoryPage {
}
typeModel = Model.of(ticket.type);
- titleModel = Model.of(ticket.title);
- topicModel = Model.of(ticket.topic == null ? "" : ticket.topic);
+ titleModel = SafeTextModel.none(ticket.title);
+ topicModel = SafeTextModel.none(ticket.topic == null ? "" : ticket.topic);
responsibleModel = Model.of();
milestoneModel = Model.of();
mergeToModel = Model.of(ticket.mergeTo == null ? getRepositoryModel().mergeTo : ticket.mergeTo);
@@ -134,7 +136,7 @@ public class EditTicketPage extends RepositoryPage {
form.add(new TextField<String>("title", titleModel));
form.add(new TextField<String>("topic", topicModel));
- final IModel<String> markdownPreviewModel = new Model<String>();
+ final SafeTextModel markdownPreviewModel = new SafeTextModel(Mode.none);
descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);
descriptionPreview.setEscapeModelStrings(false);
descriptionPreview.setOutputMarkupId(true);
diff --git a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
index 961590a2..7a68febb 100644
--- a/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/NewTicketPage.java
@@ -46,6 +46,8 @@ import com.gitblit.tickets.TicketNotifier;
import com.gitblit.tickets.TicketResponsible;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.SafeTextModel;
+import com.gitblit.wicket.SafeTextModel.Mode;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.MarkdownTextArea;
@@ -87,8 +89,8 @@ public class NewTicketPage extends RepositoryPage {
}
typeModel = Model.of(TicketModel.Type.defaultType);
- titleModel = Model.of();
- topicModel = Model.of();
+ titleModel = SafeTextModel.none();
+ topicModel = SafeTextModel.none();
mergeToModel = Model.of(Repository.shortenRefName(getRepositoryModel().mergeTo));
responsibleModel = Model.of();
milestoneModel = Model.of();
@@ -103,7 +105,7 @@ public class NewTicketPage extends RepositoryPage {
form.add(new TextField<String>("title", titleModel));
form.add(new TextField<String>("topic", topicModel));
- final IModel<String> markdownPreviewModel = new Model<String>();
+ final SafeTextModel markdownPreviewModel = new SafeTextModel(Mode.none);
descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);
descriptionPreview.setEscapeModelStrings(false);
descriptionPreview.setOutputMarkupId(true);
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
index 253c4fe4..2bd9dc6c 100644
--- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java
@@ -550,7 +550,8 @@ public abstract class RepositoryPage extends RootPage {
String html;
switch (model.commitMessageRenderer) {
case MARKDOWN:
- html = MessageFormat.format("<div class='commit_message'>{0}</div>", content);
+ String safeContent = app().xssFilter().relaxed(content);
+ html = MessageFormat.format("<div class='commit_message'>{0}</div>", safeContent);
break;
default:
html = MessageFormat.format("<pre class='commit_message'>{0}</pre>", content);
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
index 090c0952..3cfa152e 100644
--- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
@@ -138,7 +138,7 @@ public class SummaryPage extends RepositoryPage {
MarkupDocument markupDoc = null;
RevCommit head = JGitUtils.getCommit(r, null);
if (head != null) {
- MarkupProcessor processor = new MarkupProcessor(app().settings());
+ MarkupProcessor processor = new MarkupProcessor(app().settings(), app().xssFilter());
markupDoc = processor.getReadme(r, repositoryName, getBestCommitId(head));
}
if (markupDoc == null || markupDoc.markup == null) {
diff --git a/src/main/java/com/gitblit/wicket/panels/CommentPanel.java b/src/main/java/com/gitblit/wicket/panels/CommentPanel.java
index 1d49ff0f..130e7336 100644
--- a/src/main/java/com/gitblit/wicket/panels/CommentPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/CommentPanel.java
@@ -19,13 +19,14 @@ import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.TicketModel;
import com.gitblit.models.TicketModel.Change;
import com.gitblit.models.UserModel;
+import com.gitblit.wicket.SafeTextModel;
+import com.gitblit.wicket.SafeTextModel.Mode;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.pages.BasePage;
@@ -89,7 +90,7 @@ public class CommentPanel extends BasePanel {
}
}.setVisible(ticket != null && ticket.number > 0));
- final IModel<String> markdownPreviewModel = new Model<String>();
+ final SafeTextModel markdownPreviewModel = new SafeTextModel(Mode.none);
markdownPreview = new Label("markdownPreview", markdownPreviewModel);
markdownPreview.setEscapeModelStrings(false);
markdownPreview.setOutputMarkupId(true);
diff --git a/src/main/java/com/gitblit/wicket/panels/MarkdownTextArea.java b/src/main/java/com/gitblit/wicket/panels/MarkdownTextArea.java
index f26f7fbe..6e06e5bb 100644
--- a/src/main/java/com/gitblit/wicket/panels/MarkdownTextArea.java
+++ b/src/main/java/com/gitblit/wicket/panels/MarkdownTextArea.java
@@ -20,12 +20,12 @@ import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.TextArea;
-import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.time.Duration;
import com.gitblit.utils.MarkdownUtils;
import com.gitblit.wicket.GitBlitWebApp;
+import com.gitblit.wicket.SafeTextModel;
public class MarkdownTextArea extends TextArea {
@@ -35,7 +35,7 @@ public class MarkdownTextArea extends TextArea {
protected String text = "";
- public MarkdownTextArea(String id, final IModel<String> previewModel, final Label previewLabel) {
+ public MarkdownTextArea(String id, final SafeTextModel previewModel, final Label previewLabel) {
super(id);
setModel(new PropertyModel(this, "text"));
add(new AjaxFormComponentUpdatingBehavior("onblur") {
@@ -65,7 +65,7 @@ public class MarkdownTextArea extends TextArea {
setOutputMarkupId(true);
}
- protected void renderPreview(IModel<String> previewModel) {
+ protected void renderPreview(SafeTextModel previewModel) {
if (text == null) {
return;
}
diff --git a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
index f1d2711e..0cdee6cb 100644
--- a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
+++ b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
@@ -26,6 +26,8 @@ import com.gitblit.manager.RuntimeManager;
import com.gitblit.manager.UserManager;
import com.gitblit.models.UserModel;
import com.gitblit.tests.mock.MemorySettings;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Class for testing local authentication.
@@ -42,7 +44,8 @@ public class AuthenticationManagerTest extends GitblitUnitTest {
}
IAuthenticationManager newAuthenticationManager() {
- RuntimeManager runtime = new RuntimeManager(getSettings(), GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start();
users = new UserManager(runtime, null).start();
AuthenticationManager auth = new AuthenticationManager(runtime, users).start();
return auth;
diff --git a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java
index cc404abf..0a5de196 100644
--- a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java
+++ b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java
@@ -29,6 +29,8 @@ import com.gitblit.manager.UserManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.tickets.BranchTicketService;
import com.gitblit.tickets.ITicketService;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Tests the branch ticket service.
@@ -50,8 +52,8 @@ public class BranchTicketServiceTest extends TicketServiceTest {
protected ITicketService getService(boolean deleteAll) throws Exception {
IStoredSettings settings = getSettings(deleteAll);
-
- IRuntimeManager runtimeManager = new RuntimeManager(settings).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter).start();
IPluginManager pluginManager = new PluginManager(runtimeManager).start();
INotificationManager notificationManager = new NotificationManager(settings).start();
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start();
diff --git a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java
index 6ede042a..1fb2eed9 100644
--- a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java
+++ b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java
@@ -29,6 +29,8 @@ import com.gitblit.manager.UserManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.tickets.FileTicketService;
import com.gitblit.tickets.ITicketService;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Tests the file ticket service.
@@ -49,8 +51,8 @@ public class FileTicketServiceTest extends TicketServiceTest {
protected ITicketService getService(boolean deleteAll) throws Exception {
IStoredSettings settings = getSettings(deleteAll);
-
- IRuntimeManager runtimeManager = new RuntimeManager(settings).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter).start();
IPluginManager pluginManager = new PluginManager(runtimeManager).start();
INotificationManager notificationManager = new NotificationManager(settings).start();
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start();
diff --git a/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java b/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java
index f4e24d4e..e2bb764e 100644
--- a/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java
+++ b/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java
@@ -32,6 +32,8 @@ import com.gitblit.manager.RuntimeManager;
import com.gitblit.manager.UserManager;
import com.gitblit.models.UserModel;
import com.gitblit.tests.mock.MemorySettings;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Test the Htpasswd user service.
@@ -74,7 +76,8 @@ public class HtpasswdAuthenticationTest extends GitblitUnitTest {
}
private HtpasswdAuthProvider newHtpasswdAuthentication(IStoredSettings settings) {
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
UserManager users = new UserManager(runtime, null).start();
HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider();
htpasswd.setup(runtime, users);
@@ -82,7 +85,8 @@ public class HtpasswdAuthenticationTest extends GitblitUnitTest {
}
private AuthenticationManager newAuthenticationManager(IStoredSettings settings) {
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
UserManager users = new UserManager(runtime, null).start();
HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider();
htpasswd.setup(runtime, users);
diff --git a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
index 646f7e9f..7c84ecc2 100644
--- a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
+++ b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
@@ -39,6 +39,8 @@ import com.gitblit.manager.UserManager;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.tests.mock.MemorySettings;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
@@ -96,7 +98,8 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
}
private LdapAuthProvider newLdapAuthentication(IStoredSettings settings) {
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
userManager = new UserManager(runtime, null).start();
LdapAuthProvider ldap = new LdapAuthProvider();
ldap.setup(runtime, userManager);
@@ -104,7 +107,8 @@ public class LdapAuthenticationTest extends GitblitUnitTest {
}
private AuthenticationManager newAuthenticationManager(IStoredSettings settings) {
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
AuthenticationManager auth = new AuthenticationManager(runtime, userManager);
auth.addAuthenticationProvider(newLdapAuthentication(settings));
return auth;
diff --git a/src/test/java/com/gitblit/tests/LuceneExecutorTest.java b/src/test/java/com/gitblit/tests/LuceneExecutorTest.java
index 5c319e65..a8358b99 100644
--- a/src/test/java/com/gitblit/tests/LuceneExecutorTest.java
+++ b/src/test/java/com/gitblit/tests/LuceneExecutorTest.java
@@ -34,6 +34,8 @@ import com.gitblit.service.LuceneService;
import com.gitblit.tests.mock.MemorySettings;
import com.gitblit.utils.FileUtils;
import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Tests Lucene indexing and querying.
@@ -48,7 +50,8 @@ public class LuceneExecutorTest extends GitblitUnitTest {
private LuceneService newLuceneExecutor() {
MemorySettings settings = new MemorySettings();
settings.put(Keys.git.repositoriesFolder, GitBlitSuite.REPOSITORIES);
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
UserManager users = new UserManager(runtime, null).start();
RepositoryManager repos = new RepositoryManager(runtime, null, users);
return new LuceneService(settings, repos);
diff --git a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java
index b782b449..48011ade 100644
--- a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java
+++ b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java
@@ -30,6 +30,8 @@ import com.gitblit.manager.UserManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.tickets.ITicketService;
import com.gitblit.tickets.RedisTicketService;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
/**
* Tests the Redis ticket service.
@@ -57,8 +59,8 @@ public class RedisTicketServiceTest extends TicketServiceTest {
protected ITicketService getService(boolean deleteAll) throws Exception {
IStoredSettings settings = getSettings(deleteAll);
-
- IRuntimeManager runtimeManager = new RuntimeManager(settings).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ IRuntimeManager runtimeManager = new RuntimeManager(settings, xssFilter).start();
IPluginManager pluginManager = new PluginManager(runtimeManager).start();
INotificationManager notificationManager = new NotificationManager(settings).start();
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start();
diff --git a/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java b/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java
index 3b6b7bba..ad773b7a 100644
--- a/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java
+++ b/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java
@@ -13,6 +13,8 @@ import com.gitblit.manager.RuntimeManager;
import com.gitblit.manager.UserManager;
import com.gitblit.models.UserModel;
import com.gitblit.tests.mock.MemorySettings;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
public class RedmineAuthenticationTest extends GitblitUnitTest {
@@ -25,7 +27,8 @@ public class RedmineAuthenticationTest extends GitblitUnitTest {
}
RedmineAuthProvider newRedmineAuthentication(IStoredSettings settings) {
- RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(settings, xssFilter, GitBlitSuite.BASEFOLDER).start();
UserManager users = new UserManager(runtime, null).start();
RedmineAuthProvider redmine = new RedmineAuthProvider();
redmine.setup(runtime, users);
@@ -37,7 +40,8 @@ public class RedmineAuthenticationTest extends GitblitUnitTest {
}
AuthenticationManager newAuthenticationManager() {
- RuntimeManager runtime = new RuntimeManager(getSettings(), GitBlitSuite.BASEFOLDER).start();
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start();
UserManager users = new UserManager(runtime, null).start();
RedmineAuthProvider redmine = new RedmineAuthProvider();
redmine.setup(runtime, users);
diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
index 9a71c884..8897ef7e 100644
--- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
+++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java
@@ -28,6 +28,8 @@ import com.gitblit.manager.IRuntimeManager;
import com.gitblit.models.ServerSettings;
import com.gitblit.models.ServerStatus;
import com.gitblit.models.SettingModel;
+import com.gitblit.utils.XssFilter;
+import com.gitblit.utils.XssFilter.AllowXssFilter;
import com.google.inject.Injector;
public class MockRuntimeManager implements IRuntimeManager {
@@ -134,6 +136,11 @@ public class MockRuntimeManager implements IRuntimeManager {
}
@Override
+ public XssFilter getXssFilter() {
+ return new AllowXssFilter();
+ }
+
+ @Override
public boolean updateSettings(Map<String, String> updatedSettings) {
return settings.saveSettings(updatedSettings);
}