From cf2ef78a8acd56363991c234830a7fe3f9d63651 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Wed, 03 Jul 2013 10:01:49 -0400
Subject: [PATCH] Retrieve summary and metric charts over https (issue-61)

---
 src/main/java/com/gitblit/wicket/pages/SummaryPage.java                |    4 
 releases.moxie                                                         |    1 
 src/main/java/com/gitblit/wicket/charting/SecureChart.java             |  633 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/main/java/com/gitblit/wicket/pages/MetricsPage.java                |    8 
 src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java |   99 +++++++
 5 files changed, 739 insertions(+), 6 deletions(-)

diff --git a/releases.moxie b/releases.moxie
index 5cfae90..8567979 100644
--- a/releases.moxie
+++ b/releases.moxie
@@ -36,6 +36,7 @@
 	 - Fixed submodule diff display
 
 	changes:
+	 - Retrieve summary and metric graphs from Google over https (issue-61)
 	 - Persist originRepository (for forks) in the repository config instead of relying on parsing origin urls which are susceptible to filesystem relocation (issue 190) 
 	 - Improved error logging for servlet containers which provide a null contextFolder (issue 199)
 	 - Improve Gerrit change ref decoration in the refs panel (issue 206)
diff --git a/src/main/java/com/gitblit/wicket/charting/SecureChart.java b/src/main/java/com/gitblit/wicket/charting/SecureChart.java
new file mode 100644
index 0000000..60dae4b
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/charting/SecureChart.java
@@ -0,0 +1,633 @@
+/*
+ * Copyright 2007 Daniel Spiewak.
+ * 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.charting;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebComponent;
+import org.wicketstuff.googlecharts.ChartDataEncoding;
+import org.wicketstuff.googlecharts.IChartAxis;
+import org.wicketstuff.googlecharts.IChartData;
+import org.wicketstuff.googlecharts.IChartFill;
+import org.wicketstuff.googlecharts.IChartGrid;
+import org.wicketstuff.googlecharts.IChartProvider;
+import org.wicketstuff.googlecharts.IFillArea;
+import org.wicketstuff.googlecharts.ILineStyle;
+import org.wicketstuff.googlecharts.ILinearGradientFill;
+import org.wicketstuff.googlecharts.ILinearStripesFill;
+import org.wicketstuff.googlecharts.IRangeMarker;
+import org.wicketstuff.googlecharts.IShapeMarker;
+import org.wicketstuff.googlecharts.ISolidFill;
+import org.wicketstuff.googlecharts.Range;
+
+/**
+ * This is a fork of org.wicketstuff.googlecharts.Chart whose only purpose
+ * is to build https urls instead of http urls.
+ * 
+ * @author Daniel Spiewak
+ * @author James Moger
+ */
+public class SecureChart extends WebComponent implements Serializable {
+
+    private static final long serialVersionUID = 6286305912682861488L;
+    private IChartProvider provider;
+    private StringBuilder url;
+    private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+    public SecureChart(String id, IChartProvider provider) {
+        super(id);
+
+        this.provider = provider;
+    }
+
+    public void invalidate() {
+        lock.writeLock().lock();
+        try {
+            url = null;
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    public CharSequence constructURL() {
+        lock.writeLock().lock();
+        try {
+            if (url != null) {
+                return url;
+            }
+
+            url = new StringBuilder("https://chart.googleapis.com/chart?");
+
+            addParameter(url, "chs", render(provider.getSize()));
+            addParameter(url, "chd", render(provider.getData()));
+            addParameter(url, "cht", render(provider.getType()));
+            addParameter(url, "chbh", render(provider.getBarWidth(), provider.getBarGroupSpacing()));
+            addParameter(url, "chtt", render(provider.getTitle()));
+            addParameter(url, "chdl", render(provider.getLegend()));
+            addParameter(url, "chco", render(provider.getColors()));
+
+            IChartFill bgFill = provider.getBackgroundFill();
+            IChartFill fgFill = provider.getChartFill();
+
+            StringBuilder fillParam = new StringBuilder();
+
+            if (bgFill != null) {
+                fillParam.append("bg,").append(render(bgFill));
+            }
+
+            if (fgFill != null) {
+                if (fillParam.length() > 0) {
+                    fillParam.append('|');
+                }
+
+                fillParam.append("c,").append(render(fgFill));
+            }
+
+            if (fillParam.toString().trim().equals("")) {
+                fillParam = null;
+            }
+
+            addParameter(url, "chf", fillParam);
+
+            IChartAxis[] axes = provider.getAxes();
+            addParameter(url, "chxt", renderTypes(axes));
+            addParameter(url, "chxl", renderLabels(axes));
+            addParameter(url, "chxp", renderPositions(axes));
+            addParameter(url, "chxr", renderRanges(axes));
+            addParameter(url, "chxs", renderStyles(axes));
+
+            addParameter(url, "chg", render(provider.getGrid()));
+            addParameter(url, "chm", render(provider.getShapeMarkers()));
+            addParameter(url, "chm", render(provider.getRangeMarkers()));
+            addParameter(url, "chls", render(provider.getLineStyles()));
+            addParameter(url, "chm", render(provider.getFillAreas()));
+            addParameter(url, "chl", render(provider.getPieLabels()));
+
+            return url;
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+
+    private void addParameter(StringBuilder url, CharSequence param, CharSequence value) {
+        if (value == null || value.length() == 0) {
+            return;
+        }
+
+        if (url.charAt(url.length() - 1) != '?') {
+            url.append('&');
+        }
+
+        url.append(param).append('=').append(value);
+    }
+    
+    private CharSequence convert(ChartDataEncoding encoding, double value, double max) {
+    	switch (encoding) {
+    	case TEXT:
+    		return SecureChartDataEncoding.TEXT.convert(value, max);
+    	case EXTENDED:
+    		return SecureChartDataEncoding.EXTENDED.convert(value, max);
+    	case SIMPLE:
+    	default:
+    		return SecureChartDataEncoding.SIMPLE.convert(value, max);
+    	}
+    }
+
+    private CharSequence render(Dimension dim) {
+        if (dim == null) {
+            return null;
+        }
+
+        return new StringBuilder().append(dim.width).append('x').append(dim.height);
+    }
+
+    private CharSequence render(IChartData data) {
+        if (data == null) {
+            return null;
+        }
+
+        ChartDataEncoding encoding = data.getEncoding();
+
+        StringBuilder back = new StringBuilder();
+        back.append(render(encoding)).append(':');
+
+        for (double[] set : data.getData()) {
+            if (set == null || set.length == 0) {
+                back.append(convert(encoding, -1, data.getMax()));
+            } else {
+                for (double value : set) {
+                    back.append(convert(encoding, value, data.getMax())).append(encoding.getValueSeparator());
+                }
+
+                if (back.substring(back.length() - encoding.getValueSeparator().length(),
+                        back.length()).equals(encoding.getValueSeparator())) {
+                    back.setLength(back.length() - encoding.getValueSeparator().length());
+                }
+            }
+
+            back.append(encoding.getSetSeparator());
+        }
+
+        if (back.substring(back.length() - encoding.getSetSeparator().length(),
+                back.length()).equals(encoding.getSetSeparator())) {
+            back.setLength(back.length() - encoding.getSetSeparator().length());
+        }
+
+        return back;
+    }
+
+    private CharSequence render(Enum<?> value) {
+        if (value == null) {
+            return null;
+        }
+
+        try {
+            Object back = value.getClass().getMethod("getRendering").invoke(value);
+
+            if (back != null) {
+                return back.toString();
+            }
+        } catch (IllegalArgumentException e) {
+        } catch (SecurityException e) {
+        } catch (IllegalAccessException e) {
+        } catch (InvocationTargetException e) {
+        } catch (NoSuchMethodException e) {
+        }
+
+        return null;
+    }
+
+    private CharSequence render(int barWidth, int groupSpacing) {
+        if (barWidth == -1) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder(barWidth);
+
+        if (groupSpacing >= 0) {
+            back.append(',').append(groupSpacing);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(String[] values) {
+        if (values == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (String value : values) {
+            CharSequence toRender = render(value);
+            if (toRender == null) {
+                toRender = "";
+            }
+
+            back.append(toRender).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(String value) {
+        if (value == null) {
+            return value;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (char c : value.toCharArray()) {
+            if (c == ' ') {
+                back.append('+');
+            } else {
+                back.append(c);
+            }
+        }
+
+        return back;
+    }
+
+    private CharSequence render(Color[] values) {
+        if (values == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (Color value : values) {
+            CharSequence toRender = render(value);
+            if (toRender == null) {
+                toRender = "";
+            }
+
+            back.append(toRender).append(',');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(Color value) {
+        if (value == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        {
+            String toPad = Integer.toHexString(value.getRed());
+
+            if (toPad.length() == 1) {
+                back.append(0);
+            }
+            back.append(toPad);
+        }
+
+        {
+            String toPad = Integer.toHexString(value.getGreen());
+
+            if (toPad.length() == 1) {
+                back.append(0);
+            }
+            back.append(toPad);
+        }
+
+        {
+            String toPad = Integer.toHexString(value.getBlue());
+
+            if (toPad.length() == 1) {
+                back.append(0);
+            }
+            back.append(toPad);
+        }
+
+        {
+            String toPad = Integer.toHexString(value.getAlpha());
+
+            if (toPad.length() == 1) {
+                back.append(0);
+            }
+            back.append(toPad);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(IChartFill fill) {
+        if (fill == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        if (fill instanceof ISolidFill) {
+            ISolidFill solidFill = (ISolidFill) fill;
+
+            back.append("s,");
+            back.append(render(solidFill.getColor()));
+        } else if (fill instanceof ILinearGradientFill) {
+            ILinearGradientFill gradientFill = (ILinearGradientFill) fill;
+
+            back.append("lg,").append(gradientFill.getAngle()).append(',');
+
+            Color[] colors = gradientFill.getColors();
+            double[] offsets = gradientFill.getOffsets();
+            for (int i = 0; i < colors.length; i++) {
+                back.append(render(colors[i])).append(',').append(offsets[i]).append(',');
+            }
+
+            back.setLength(back.length() - 1);
+        } else if (fill instanceof ILinearStripesFill) {
+            ILinearStripesFill stripesFill = (ILinearStripesFill) fill;
+
+            back.append("ls,").append(stripesFill.getAngle()).append(',');
+
+            Color[] colors = stripesFill.getColors();
+            double[] widths = stripesFill.getWidths();
+            for (int i = 0; i < colors.length; i++) {
+                back.append(render(colors[i])).append(',').append(widths[i]).append(',');
+            }
+
+            back.setLength(back.length() - 1);
+        } else {
+            return null;
+        }
+
+        return back;
+    }
+
+    private CharSequence renderTypes(IChartAxis[] axes) {
+        if (axes == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (IChartAxis axis : axes) {
+            back.append(render(axis.getType())).append(',');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence renderLabels(IChartAxis[] axes) {
+        if (axes == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (int i = 0; i < axes.length; i++) {
+            if (axes[i] == null || axes[i].getLabels() == null) {
+                continue;
+            }
+
+            back.append(i).append(":|");
+
+            for (String label : axes[i].getLabels()) {
+                if (label == null) {
+                    back.append('|');
+                    continue;
+                }
+
+                back.append(render(label)).append('|');
+            }
+
+            if (i == axes.length - 1) {
+                back.setLength(back.length() - 1);
+            }
+        }
+
+        return back;
+    }
+
+    private CharSequence renderPositions(IChartAxis[] axes) {
+        if (axes == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (int i = 0; i < axes.length; i++) {
+            if (axes[i] == null || axes[i].getPositions() == null) {
+                continue;
+            }
+
+            back.append(i).append(',');
+
+            for (double position : axes[i].getPositions()) {
+                back.append(position).append(',');
+            }
+
+            back.setLength(back.length() - 1);
+
+            back.append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence renderRanges(IChartAxis[] axes) {
+        if (axes == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (int i = 0; i < axes.length; i++) {
+            if (axes[i] == null || axes[i].getRange() == null) {
+                continue;
+            }
+
+            back.append(i).append(',');
+
+            Range range = axes[i].getRange();
+            back.append(range.getStart()).append(',').append(range.getEnd()).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence renderStyles(IChartAxis[] axes) {
+        if (axes == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (int i = 0; i < axes.length; i++) {
+            if (axes[i] == null || axes[i].getColor() == null
+                    || axes[i].getFontSize() < 0 || axes[i].getAlignment() == null) {
+                continue;
+            }
+
+            back.append(i).append(',');
+            back.append(render(axes[i].getColor())).append(',');
+            back.append(axes[i].getFontSize()).append(',');
+            back.append(render(axes[i].getAlignment())).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(IChartGrid grid) {
+        if (grid == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        back.append(grid.getXStepSize()).append(',');
+        back.append(grid.getYStepSize());
+
+        if (grid.getSegmentLength() >= 0) {
+            back.append(',').append(grid.getSegmentLength());
+            back.append(',').append(grid.getBlankLength());
+        }
+
+        return back;
+    }
+
+    private CharSequence render(IShapeMarker[] markers) {
+        if (markers == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (IShapeMarker marker : markers) {
+            back.append(render(marker.getType())).append(',');
+            back.append(render(marker.getColor())).append(',');
+            back.append(marker.getIndex()).append(',');
+            back.append(marker.getPoint()).append(',');
+            back.append(marker.getSize()).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(IRangeMarker[] markers) {
+        if (markers == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (IRangeMarker marker : markers) {
+            back.append(render(marker.getType())).append(',');
+            back.append(render(marker.getColor())).append(',');
+            back.append(0).append(',');
+            back.append(marker.getStart()).append(',');
+            back.append(marker.getEnd()).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(IFillArea[] areas) {
+        if (areas == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (IFillArea area : areas) {
+            back.append(render(area.getType())).append(',');
+            back.append(render(area.getColor())).append(',');
+            back.append(area.getStartIndex()).append(',');
+            back.append(area.getEndIndex()).append(',');
+            back.append(0).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    private CharSequence render(ILineStyle[] styles) {
+        if (styles == null) {
+            return null;
+        }
+
+        StringBuilder back = new StringBuilder();
+
+        for (ILineStyle style : styles) {
+            if (style == null) {
+                back.append('|');
+                continue;
+            }
+
+            back.append(style.getThickness()).append(',');
+            back.append(style.getSegmentLength()).append(',');
+            back.append(style.getBlankLength()).append('|');
+        }
+
+        if (back.length() > 0) {
+            back.setLength(back.length() - 1);
+        }
+
+        return back;
+    }
+
+    @Override
+    protected void onComponentTag(ComponentTag tag) {
+        checkComponentTag(tag, "img");
+        super.onComponentTag(tag);
+
+        tag.put("src", constructURL());
+    }
+}
diff --git a/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java b/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java
new file mode 100644
index 0000000..90a0596
--- /dev/null
+++ b/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2007 Daniel Spiewak.
+ * 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.charting;
+
+/**
+ * This class is a pristine fork of org.wicketstuff.googlecharts.ChartDataEncoding
+ * to bring the package-protected convert methods to SecureChart.
+ * 
+ * @author Daniel Spiewak
+ */
+public enum SecureChartDataEncoding {
+
+    SIMPLE("s", "", ",") {
+
+        CharSequence convert(double value, double max) {
+            if (value < 0) {
+                return "_";
+            }
+
+            value = Math.round((CHARS.length() - 1) * value / max);
+
+            if (value > CHARS.length() - 1) {
+                throw new IllegalArgumentException(value + " is out of range for SIMPLE encoding");
+            }
+
+            return Character.toString(CHARS.charAt((int) value));
+        }
+    },
+    TEXT("t", ",", "|") {
+
+    	CharSequence convert(double value, double max) {
+            if (value < 0) {
+                value = -1;
+            }
+
+            if (value > 100) {
+                throw new IllegalArgumentException(value + " is out of range for TEXT encoding");
+            }
+
+            return Double.toString(value);
+        }
+    },
+    EXTENDED("e", "", ",") {
+
+    	CharSequence convert(double value, double max) {
+            if (value < 0) {
+                return "__";
+            }
+
+            value = Math.round(value);
+
+            if (value > (EXT_CHARS.length() - 1) * (EXT_CHARS.length() - 1)) {
+                throw new IllegalArgumentException(value + " is out of range for EXTENDED encoding");
+            }
+
+            int rem = (int) (value % EXT_CHARS.length());
+            int exp = (int) (value / EXT_CHARS.length());
+
+            return new StringBuilder().append(EXT_CHARS.charAt(exp)).append(EXT_CHARS.charAt(rem));
+        }
+    };
+    private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    private static final String EXT_CHARS = CHARS + "-_.";
+    private final String rendering, valueSeparator, setSeparator;
+
+    private SecureChartDataEncoding(String rendering, String valueSeparator, String setSeparator) {
+        this.rendering = rendering;
+        this.valueSeparator = valueSeparator;
+        this.setSeparator = setSeparator;
+    }
+
+    public String getRendering() {
+        return rendering;
+    }
+
+    public String getValueSeparator() {
+        return valueSeparator;
+    }
+
+    public String getSetSeparator() {
+        return setSeparator;
+    }
+
+    abstract CharSequence convert(double value, double max);
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/MetricsPage.java b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java
index ce75f53..3195020 100644
--- a/src/main/java/com/gitblit/wicket/pages/MetricsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java
@@ -28,7 +28,6 @@
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.markup.html.basic.Label;
 import org.eclipse.jgit.lib.Repository;
-import org.wicketstuff.googlecharts.Chart;
 import org.wicketstuff.googlecharts.ChartAxis;
 import org.wicketstuff.googlecharts.ChartAxisType;
 import org.wicketstuff.googlecharts.ChartProvider;
@@ -42,6 +41,7 @@
 import com.gitblit.utils.MetricUtils;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.charting.SecureChart;
 
 public class MetricsPage extends RepositoryPage {
 
@@ -87,7 +87,7 @@
 			provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
 			provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.decode("#002060"), 1, -1, 5));
 
-			add(new Chart(wicketId, provider));
+			add(new SecureChart(wicketId, provider));
 		} else {
 			add(WicketUtils.newBlankImage(wicketId));
 		}
@@ -112,7 +112,7 @@
 					String.valueOf((int) WicketUtils.maxValue(metrics)) });
 			provider.addAxis(commitAxis);
 
-			add(new Chart(wicketId, provider));
+			add(new SecureChart(wicketId, provider));
 		} else {
 			add(WicketUtils.newBlankImage(wicketId));
 		}
@@ -127,7 +127,7 @@
 			}
 			ChartProvider provider = new ChartProvider(new Dimension(800, 200), ChartType.PIE, data);
 			provider.setPieLabels(labels.toArray(new String[labels.size()]));
-			add(new Chart(wicketId, provider));
+			add(new SecureChart(wicketId, provider));
 		} else {
 			add(WicketUtils.newBlankImage(wicketId));
 		}
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
index 1934682..1afa967 100644
--- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java
@@ -32,7 +32,6 @@
 import org.apache.wicket.markup.repeater.data.ListDataProvider;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.wicketstuff.googlecharts.Chart;
 import org.wicketstuff.googlecharts.ChartAxis;
 import org.wicketstuff.googlecharts.ChartAxisType;
 import org.wicketstuff.googlecharts.ChartProvider;
@@ -53,6 +52,7 @@
 import com.gitblit.utils.StringUtils;
 import com.gitblit.wicket.GitBlitWebSession;
 import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.charting.SecureChart;
 import com.gitblit.wicket.panels.BranchesPanel;
 import com.gitblit.wicket.panels.LinkPanel;
 import com.gitblit.wicket.panels.LogPanel;
@@ -204,7 +204,7 @@
 			provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
 			provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.decode("#002060"), 1, -1, 5));
 
-			add(new Chart("commitsChart", provider));
+			add(new SecureChart("commitsChart", provider));
 		} else {
 			add(WicketUtils.newBlankImage("commitsChart"));
 		}

--
Gitblit v1.9.1