--- /dev/null
+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());
+ }
+}
import com.gitblit.tickets.TicketResponsible;\r
import com.gitblit.utils.StringUtils;\r
import com.gitblit.wicket.GitBlitWebSession;\r
+import com.gitblit.wicket.SafeTextModel;\r
+import com.gitblit.wicket.SafeTextModel.Mode;\r
import com.gitblit.wicket.WicketUtils;\r
import com.gitblit.wicket.panels.MarkdownTextArea;\r
\r
}\r
\r
typeModel = Model.of(ticket.type);\r
- titleModel = Model.of(ticket.title);\r
- topicModel = Model.of(ticket.topic == null ? "" : ticket.topic);\r
+ titleModel = SafeTextModel.none(ticket.title);\r
+ topicModel = SafeTextModel.none(ticket.topic == null ? "" : ticket.topic);\r
responsibleModel = Model.of();\r
milestoneModel = Model.of();\r
mergeToModel = Model.of(ticket.mergeTo == null ? getRepositoryModel().mergeTo : ticket.mergeTo);\r
form.add(new TextField<String>("title", titleModel));\r
form.add(new TextField<String>("topic", topicModel));\r
\r
- final IModel<String> markdownPreviewModel = new Model<String>();\r
+ final SafeTextModel markdownPreviewModel = new SafeTextModel(Mode.none);\r
descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);\r
descriptionPreview.setEscapeModelStrings(false);\r
descriptionPreview.setOutputMarkupId(true);\r
import com.gitblit.tickets.TicketResponsible;\r
import com.gitblit.utils.StringUtils;\r
import com.gitblit.wicket.GitBlitWebSession;\r
+import com.gitblit.wicket.SafeTextModel;\r
+import com.gitblit.wicket.SafeTextModel.Mode;\r
import com.gitblit.wicket.WicketUtils;\r
import com.gitblit.wicket.panels.MarkdownTextArea;\r
\r
}\r
\r
typeModel = Model.of(TicketModel.Type.defaultType);\r
- titleModel = Model.of();\r
- topicModel = Model.of();\r
+ titleModel = SafeTextModel.none();\r
+ topicModel = SafeTextModel.none();\r
mergeToModel = Model.of(Repository.shortenRefName(getRepositoryModel().mergeTo));\r
responsibleModel = Model.of();\r
milestoneModel = Model.of();\r
form.add(new TextField<String>("title", titleModel));\r
form.add(new TextField<String>("topic", topicModel));\r
\r
- final IModel<String> markdownPreviewModel = new Model<String>();\r
+ final SafeTextModel markdownPreviewModel = new SafeTextModel(Mode.none);\r
descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);\r
descriptionPreview.setEscapeModelStrings(false);\r
descriptionPreview.setOutputMarkupId(true);\r
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;
}
}.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);
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 {
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") {
setOutputMarkupId(true);
}
- protected void renderPreview(IModel<String> previewModel) {
+ protected void renderPreview(SafeTextModel previewModel) {
if (text == null) {
return;
}