diff --git a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/EntryEdit.java b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/EntryEdit.java index a12dc18fff..58dd32064d 100644 --- a/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/EntryEdit.java +++ b/app/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/EntryEdit.java @@ -20,10 +20,8 @@ import java.sql.Timestamp; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -53,10 +51,6 @@ import org.apache.roller.weblogger.util.MediacastException; import org.apache.roller.weblogger.util.MediacastResource; import org.apache.roller.weblogger.util.MediacastUtil; -import org.apache.roller.weblogger.util.RollerMessages; -import org.apache.roller.weblogger.util.RollerMessages.RollerMessage; -import org.apache.roller.weblogger.util.Trackback; -import org.apache.roller.weblogger.util.TrackbackNotAllowedException; import org.apache.struts2.convention.annotation.AllowedMethods; import org.apache.struts2.interceptor.validation.SkipValidation; @@ -74,9 +68,6 @@ public final class EntryEdit extends UIAction { // the entry we are adding or editing private WeblogEntry entry = null; - // url to send trackback to - private String trackbackUrl = null; - public EntryEdit() { this.desiredMenu = "editor"; } @@ -359,70 +350,6 @@ public String getPreviewURL() { getEntry().getAnchor(), true); } - public String getTrackbackUrl() { - return trackbackUrl; - } - - public void setTrackbackUrl(String trackbackUrl) { - this.trackbackUrl = trackbackUrl; - } - - /** - * Send trackback to a specific url. - */ - @SkipValidation - public String trackback() { - - // make sure we have an entry to edit and it belongs to the action - // weblog - if (getEntry() == null) { - return ERROR; - } else if (!getEntry().getWebsite().equals(getActionWeblog())) { - return DENIED; - } - - if (!StringUtils.isEmpty(getTrackbackUrl())) { - RollerMessages results = null; - try { - Trackback trackback = new Trackback(getEntry(), - getTrackbackUrl()); - results = trackback.send(); - } catch (TrackbackNotAllowedException ex) { - addError("error.trackbackNotAllowed"); - } catch (Exception e) { - log.error("Error sending trackback", e); - // TODO: error handling - addError("error.general", e.getMessage()); - } - - if (results != null) { - for (Iterator mit = results.getMessages(); mit.hasNext();) { - RollerMessage msg = mit.next(); - if (msg.getArgs() == null) { - addMessage(msg.getKey()); - } else { - addMessage(msg.getKey(), Arrays.asList(msg.getArgs())); - } - } - - for (Iterator eit = results.getErrors(); eit.hasNext();) { - RollerMessage err = eit.next(); - if (err.getArgs() == null) { - addError(err.getKey()); - } else { - addError(err.getKey(), Arrays.asList(err.getArgs())); - } - } - } - - // reset trackback url - setTrackbackUrl(null); - - } - - return INPUT; - } - /** * Get the list of all categories for the action weblog */ diff --git a/app/src/main/java/org/apache/roller/weblogger/util/Trackback.java b/app/src/main/java/org/apache/roller/weblogger/util/Trackback.java deleted file mode 100644 index 88753a501b..0000000000 --- a/app/src/main/java/org/apache/roller/weblogger/util/Trackback.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. The ASF licenses this file to You - * 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. For additional information regarding - * copyright in this work, please see the NOTICE file in the top level - * directory of this distribution. - */ - -package org.apache.roller.weblogger.util; - -import java.io.IOException; -import java.io.StringReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.text.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.roller.util.RollerConstants; -import org.apache.roller.weblogger.WebloggerException; -import org.apache.roller.weblogger.config.WebloggerConfig; -import org.apache.roller.weblogger.pojos.WeblogEntry; -import org.jdom2.Document; -import org.jdom2.Element; -import org.jdom2.JDOMException; -import org.jdom2.input.SAXBuilder; - - -/** - * Represents a trackback request. - */ -public class Trackback { - - private static final Log LOG = LogFactory.getLog(Trackback.class); - - private final WeblogEntry entry; - private final String trackbackURL; - - - public Trackback(WeblogEntry tEntry, String tURL) - throws TrackbackNotAllowedException { - - // Make sure trackback to URL is allowed - boolean allowTrackback = true; - String allowedURLs = WebloggerConfig.getProperty("trackback.allowedURLs"); - if (!StringUtils.isEmpty(allowedURLs)) { - // in the case that the administrator has enabled trackbacks - // for only specific URLs, set it to false by default - allowTrackback = false; - String[] splitURLs = allowedURLs.split("\\|\\|"); - for (int i=0; i < splitURLs.length; i++) { - Matcher m = Pattern.compile(splitURLs[i]).matcher(tURL); - if (m.matches()) { - allowTrackback = true; - break; - } - } - } - - if(!allowTrackback) { - throw new TrackbackNotAllowedException(tURL); - } else { - // test url - try { - new URL(tURL); - } catch(MalformedURLException ex) { - // bad url - throw new IllegalArgumentException("bad url: "+tURL); - } - - entry = tEntry; - trackbackURL = tURL; - } - - } - - - /** - * Sends trackback from entry to remote URL. - * See Trackback spec for details: http://www.sixapart.com/pronet/docs/trackback_spec - */ - public RollerMessages send() throws WebloggerException { - - RollerMessages messages = new RollerMessages(); - - LOG.debug("Sending trackback to url - " + trackbackURL); - - // Construct data - String title = entry.getTitle(); - String excerpt = StringUtils.left( Utilities.removeHTML(entry.getDisplayContent()), - RollerConstants.TEXTWIDTH_255); - String url = entry.getPermalink(); - String blog_name = entry.getWebsite().getName(); - - // build trackback post parameters as query string - Map params = Map.of("title", URLUtilities.encode(title), - "excerpt", URLUtilities.encode(excerpt), - "url", URLUtilities.encode(url), - "blog_name", URLUtilities.encode(blog_name)); - String queryString = URLUtilities.getQueryString(params); - - LOG.debug("query string - " + queryString); - - // prepare http request - HttpClient client = new HttpClient(); - client.setConnectionTimeout(45 * RollerConstants.SEC_IN_MS); - HttpMethod method = new PostMethod(trackbackURL); - method.setQueryString(queryString); - - try { - // execute trackback - int statusCode = client.executeMethod(method); - - // read response - byte[] response = method.getResponseBody(); - String responseString = Utilities.escapeHTML(new String(response, StandardCharsets.UTF_8)); - - LOG.debug("result = " + statusCode + " " + method.getStatusText()); - LOG.debug("response:\n" + responseString); - - if(statusCode == HttpStatus.SC_OK) { - // trackback request succeeded, message will give details - try { - messages = parseTrackbackResponse(new String(response, StandardCharsets.UTF_8), messages); - } catch (Exception e) { - // Cannot parse response, indicates failure - messages.addError("weblogEdit.trackbackErrorParsing", responseString); - } - } else if(statusCode == HttpStatus.SC_NOT_FOUND) { - // 404, invalid trackback url - messages.addError("weblogEdit.trackbackError404"); - } else { - // some other kind of error with url, like 500, 403, etc - // just provide a generic error message and give the http response text - messages.addError("weblogEdit.trackbackErrorResponse", - new String[] {""+statusCode, method.getStatusText()}); - } - - } catch (IOException e) { - // some kind of transport error sending trackback post - LOG.debug("Error sending trackback", e); - messages.addError("weblogEdit.trackbackErrorTransport"); - } finally { - // release used connection - method.releaseConnection(); - } - - return messages; - } - - - /** - * Parse XML returned from trackback POST, returns error or success message - * in RollerMessages object. - */ - private RollerMessages parseTrackbackResponse(String response, RollerMessages messages) - throws JDOMException, IOException { - - SAXBuilder builder = new SAXBuilder(); - Document doc = builder.build( - new StringReader(StringEscapeUtils.unescapeHtml4(response))); - Element root = doc.getRootElement(); - - if ("response".equals(root.getName())) { - int code = -99; - try { - code = Integer.parseInt(root.getChildText("error")); - } catch (NumberFormatException ignoredByDesign) {} - - String message = root.getChildText("message"); - if (code != 0) { - messages.addError("weblogEdit.trackbackFailure", Utilities.removeHTML(message)); - } else { - messages.addMessage("weblogEdit.trackbackSuccess"); - } - } else { - messages.addError("weblogEdit.trackbackErrorParsing", Utilities.removeHTML(response)); - } - - return messages; - } - -} diff --git a/app/src/main/java/org/apache/roller/weblogger/util/TrackbackNotAllowedException.java b/app/src/main/java/org/apache/roller/weblogger/util/TrackbackNotAllowedException.java deleted file mode 100644 index f5056f6936..0000000000 --- a/app/src/main/java/org/apache/roller/weblogger/util/TrackbackNotAllowedException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. The ASF licenses this file to You - * 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. For additional information regarding - * copyright in this work, please see the NOTICE file in the top level - * directory of this distribution. - */ - -package org.apache.roller.weblogger.util; - -import org.apache.roller.weblogger.WebloggerException; - - -/** - * An exception thrown when a Trackback is formed for a url which is disallowed - * by the system administrator. - */ -public class TrackbackNotAllowedException extends WebloggerException { - - public TrackbackNotAllowedException(String url) { - super(url); - } - -} diff --git a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties index d73e7f9ca1..8fba942175 100644 --- a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties +++ b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties @@ -198,12 +198,6 @@ site.bannedwordslist.enable.trackbacks=true # enables partial bannedwordslist check (not including bannedwordslist.txt) for each incoming referrer site.bannedwordslist.enable.referrers=false -# Trackback protection. Set this only if you need to limit the URLs to -# which users may send trackbacks. Regex expressions are allowed, for example: -# trackback.allowedURLs=http://w3.ibm.com/.*||http://another.example.com/.* -trackback.allowedURLs= - - #---------------------------------- # Planet Aggregator settings diff --git a/app/src/main/resources/struts.xml b/app/src/main/resources/struts.xml index cc94ba6588..e3bab427c9 100644 --- a/app/src/main/resources/struts.xml +++ b/app/src/main/resources/struts.xml @@ -359,7 +359,7 @@ ${weblog} ${bean.id} - execute,firstSave,publish,saveDraft,trackback + execute,firstSave,publish,saveDraft menu /roller-ui - execute,firstSave,publish,saveDraft,trackback + execute,firstSave,publish,saveDraft - - <%-- Trackback control - -
-

- -
- - - -
- --%> - diff --git a/app/src/test/java/org/apache/roller/weblogger/ui/struts2/editor/EntryTrackbackRemovalTest.java b/app/src/test/java/org/apache/roller/weblogger/ui/struts2/editor/EntryTrackbackRemovalTest.java new file mode 100644 index 0000000000..961593458d --- /dev/null +++ b/app/src/test/java/org/apache/roller/weblogger/ui/struts2/editor/EntryTrackbackRemovalTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.roller.weblogger.ui.struts2.editor; + +import java.io.InputStream; +import java.util.Set; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class EntryTrackbackRemovalTest { + + @Test + void entryActionsDoNotAllowTrackbackMethod() throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + factory.setXIncludeAware(false); + factory.setExpandEntityReferences(false); + + try (InputStream input = getClass().getClassLoader().getResourceAsStream("struts.xml")) { + assertNotNull(input); + Document config = factory.newDocumentBuilder().parse(input); + NodeList actions = config.getElementsByTagName("action"); + Set expectedActions = Set.of("entryAdd", "entryEdit"); + int actionsChecked = 0; + + for (int i = 0; i < actions.getLength(); i++) { + Element action = (Element) actions.item(i); + if (expectedActions.contains(action.getAttribute("name"))) { + NodeList allowedMethods = action.getElementsByTagName("allowed-methods"); + assertEquals(1, allowedMethods.getLength()); + String methods = allowedMethods.item(0).getTextContent(); + assertFalse(Set.of(methods.trim().split("\\s*,\\s*")).contains("trackback")); + actionsChecked++; + } + } + + assertEquals(expectedActions.size(), actionsChecked); + } + } + + @Test + void outboundTrackbackImplementationIsRemoved() { + assertThrows(NoSuchMethodException.class, + () -> EntryEdit.class.getMethod("trackback")); + assertThrows(ClassNotFoundException.class, + () -> Class.forName("org.apache.roller.weblogger.util.Trackback")); + assertThrows(ClassNotFoundException.class, + () -> Class.forName( + "org.apache.roller.weblogger.util.TrackbackNotAllowedException")); + } +}