source: josm/trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java@ 10597

Last change on this file since 10597 was 10404, checked in by Don-vip, 8 years ago

findbugs security - XML Parsing Vulnerable to XXE - enable FEATURE_SECURE_PROCESSING for DOM builders

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools.bugreport;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagConstraints;
7import java.awt.GridBagLayout;
8import java.io.IOException;
9import java.io.InputStream;
10import java.net.URL;
11import java.net.URLEncoder;
12import java.nio.ByteBuffer;
13import java.nio.CharBuffer;
14import java.nio.charset.Charset;
15import java.nio.charset.StandardCharsets;
16
17import javax.swing.JOptionPane;
18import javax.swing.JPanel;
19import javax.swing.SwingUtilities;
20import javax.xml.parsers.ParserConfigurationException;
21import javax.xml.xpath.XPath;
22import javax.xml.xpath.XPathConstants;
23import javax.xml.xpath.XPathExpressionException;
24import javax.xml.xpath.XPathFactory;
25
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
28import org.openstreetmap.josm.gui.widgets.UrlLabel;
29import org.openstreetmap.josm.tools.Base64;
30import org.openstreetmap.josm.tools.GBC;
31import org.openstreetmap.josm.tools.HttpClient;
32import org.openstreetmap.josm.tools.HttpClient.Response;
33import org.openstreetmap.josm.tools.OpenBrowser;
34import org.openstreetmap.josm.tools.Utils;
35import org.w3c.dom.Document;
36import org.xml.sax.SAXException;
37
38/**
39 * This class handles sending the bug report to JOSM website.
40 * <p>
41 * Currently, we try to open a browser window for the user that displays the bug report.
42 *
43 * @author Michael Zangl
44 * @since 10055
45 */
46public class BugReportSender extends Thread {
47
48 private final String statusText;
49 private String errorMessage;
50
51 /**
52 * Creates a new sender.
53 * @param statusText The status text to send.
54 */
55 protected BugReportSender(String statusText) {
56 super("Bug report sender");
57 this.statusText = statusText;
58 }
59
60 @Override
61 public void run() {
62 try {
63 // first, send the debug text using post.
64 String debugTextPasteId = pasteDebugText();
65
66 // then open a browser to display the pasted text.
67 String openBrowserError = OpenBrowser.displayUrl(getJOSMTicketURL() + "?pdata_stored=" + debugTextPasteId);
68 if (openBrowserError != null) {
69 Main.warn(openBrowserError);
70 failed(openBrowserError);
71 }
72 } catch (BugReportSenderException e) {
73 Main.warn(e);
74 failed(e.getMessage());
75 }
76 }
77
78 /**
79 * Sends the debug text to the server.
80 * @return The token which was returned by the server. We need to pass this on to the ticket system.
81 * @throws BugReportSenderException if sending the report failed.
82 */
83 private String pasteDebugText() throws BugReportSenderException {
84 try {
85 String text = Utils.strip(statusText);
86 ByteBuffer buffer = Charset.forName("UTF-8").encode(CharBuffer.wrap(text));
87 String pdata = Base64.encode(buffer, false);
88 String postQuery = "pdata=" + URLEncoder.encode(pdata, "UTF-8");
89 HttpClient client = HttpClient.create(new URL(getJOSMTicketURL()), "POST")
90 .setHeader("Content-Type", "application/x-www-form-urlencoded")
91 .setRequestBody(postQuery.getBytes(StandardCharsets.UTF_8));
92
93 Response connection = client.connect();
94
95 if (connection.getResponseCode() >= 500) {
96 throw new BugReportSenderException("Internal server error.");
97 }
98
99 try (InputStream in = connection.getContent()) {
100 return retrieveDebugToken(Utils.parseSafeDOM(in));
101 }
102 } catch (IOException | SAXException | ParserConfigurationException | XPathExpressionException t) {
103 throw new BugReportSenderException(t);
104 }
105 }
106
107 private static String getJOSMTicketURL() {
108 return Main.getJOSMWebsite() + "/josmticket";
109 }
110
111 private static String retrieveDebugToken(Document document) throws XPathExpressionException, BugReportSenderException {
112 XPathFactory factory = XPathFactory.newInstance();
113 XPath xpath = factory.newXPath();
114 String status = (String) xpath.compile("/josmticket/@status").evaluate(document, XPathConstants.STRING);
115 if (!"ok".equals(status)) {
116 String message = (String) xpath.compile("/josmticket/error/text()").evaluate(document,
117 XPathConstants.STRING);
118 if (message.isEmpty()) {
119 message = "Error in server response but server did not tell us what happened.";
120 }
121 throw new BugReportSenderException(message);
122 }
123
124 String token = (String) xpath.compile("/josmticket/preparedid/text()")
125 .evaluate(document, XPathConstants.STRING);
126 if (token.isEmpty()) {
127 throw new BugReportSenderException("Server did not respond with a prepared id.");
128 }
129 return token;
130 }
131
132 private void failed(String string) {
133 errorMessage = string;
134 SwingUtilities.invokeLater(new Runnable() {
135 @Override
136 public void run() {
137 JPanel errorPanel = new JPanel(new GridBagLayout());
138 errorPanel.add(new JMultilineLabel(
139 tr("Opening the bug report failed. Please report manually using this website:")),
140 GBC.eol().fill(GridBagConstraints.HORIZONTAL));
141 errorPanel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket", 2), GBC.eop().insets(8, 0, 0, 0));
142 errorPanel.add(new DebugTextDisplay(statusText));
143
144 JOptionPane.showMessageDialog(Main.parent, errorPanel, tr("You have encountered a bug in JOSM"),
145 JOptionPane.ERROR_MESSAGE);
146 }
147 });
148 }
149
150 /**
151 * Returns the error message that could have occured during bug sending.
152 * @return the error message, or {@code null} if successful
153 */
154 public final String getErrorMessage() {
155 return errorMessage;
156 }
157
158 private static class BugReportSenderException extends Exception {
159 BugReportSenderException(String message) {
160 super(message);
161 }
162
163 BugReportSenderException(Throwable cause) {
164 super(cause);
165 }
166 }
167
168 /**
169 * Opens the bug report window on the JOSM server.
170 * @param statusText The status text to send along to the server.
171 * @return bug report sender started thread
172 */
173 public static BugReportSender reportBug(String statusText) {
174 BugReportSender sender = new BugReportSender(statusText);
175 sender.start();
176 return sender;
177 }
178}
Note: See TracBrowser for help on using the repository browser.