1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.xml.internal.html.filter

File LinkFilter.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

12
20
3
1
125
62
13
0.65
6.67
3
4.33

Classes

Class Line # Actions
LinkFilter 57 20 0% 13 3
0.914285791.4%
 

Contributing tests

This file is covered by 109 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.xml.internal.html.filter;
21   
22    import java.net.URI;
23    import java.net.URISyntaxException;
24    import java.util.ArrayList;
25    import java.util.Arrays;
26    import java.util.List;
27    import java.util.Map;
28   
29    import javax.inject.Named;
30    import javax.inject.Singleton;
31   
32    import org.w3c.dom.Document;
33    import org.w3c.dom.Element;
34    import org.xwiki.component.annotation.Component;
35    import org.xwiki.text.StringUtils;
36    import org.xwiki.xml.html.filter.AbstractHTMLFilter;
37   
38    /**
39    * When a link is open in an other window or in an other frame, the loaded page has some restricted access to the
40    * parent window. Among other things, it has the ability to redirect it to an other page, which can lead to
41    * dangerous phishing attacks.
42    *
43    * See: https://mathiasbynens.github.io/rel-noopener/ or https://dev.to/phishing or
44    * http://jira.xwiki.org/browse/XRENDERING-462
45    *
46    * To avoid this vulnerability, we automatically add the "noopener" value to the "rel" attribute of the anchor.
47    * But because Firefox does not handle it, we also need to add the "noreferer" value.
48    *
49    * @version $Id: 5f9f25151d8bf9c15b6ff3b9e9825c4df4516df8 $
50    * @since 7.4.5
51    * @since 8.2.2
52    * @since 8.3M2
53    */
54    @Component
55    @Named("link")
56    @Singleton
 
57    public class LinkFilter extends AbstractHTMLFilter
58    {
59    private static final String NOOPENER = "noopener";
60   
61    private static final String NOREFERRER = "noreferrer";
62   
 
63  4985 toggle @Override
64    public void filter(Document document, Map<String, String> cleaningParameters)
65    {
66    // Iterate all links and fix them.
67  4985 for (Element link : filterDescendants(document.getDocumentElement(), new String[] { TAG_A })) {
68  5103 filter(link);
69    }
70    }
71   
 
72  5103 toggle private void filter(Element link)
73    {
74    // Do not handle internal link
75  5103 if (!isExternalLink(link.getAttribute(ATTRIBUTE_HREF))) {
76  5086 return;
77    }
78   
79  17 String target = link.getAttribute(ATTRIBUTE_TARGET);
80    // Target can have these values:
81    //
82    // "_blank" which opens the link in a new window
83    // "_self" which opens the link in the same window (default)
84    // "_top" and "_parent" which control the top or the parent window of some frame
85    // "frame-name" (it could be anything) which opens the link in the frame called "frame-name".
86    //
87    // "_self", "_top" and "_parent" are the only safe values. So we need to handle any other value...
88  17 if (StringUtils.isNotBlank(target)
89    && !"_self".equals(target) && !"_parent".equals(target) && !"_top".equals(target)) {
90  6 List<String> relAttributes = new ArrayList<>();
91   
92    // Parse the current values
93  6 String relAttribute = link.getAttribute(ATTRIBUTE_REL);
94  6 if (relAttribute != null) {
95  6 relAttributes.addAll(Arrays.asList(relAttribute.split(" ")));
96    }
97   
98    // Add the "noopener" attribute
99  6 if (!relAttributes.contains(NOOPENER)) {
100  5 relAttributes.add(NOOPENER);
101    }
102   
103    // Add the "noreferrer" attribute
104  6 if (!relAttributes.contains(NOREFERRER)) {
105  5 relAttributes.add(NOREFERRER);
106    }
107   
108    // Serialize the attributes
109  6 if (!relAttributes.isEmpty()) {
110  6 link.setAttribute(ATTRIBUTE_REL, String.join(" ", relAttributes));
111    }
112    }
113    }
114   
 
115  5103 toggle private boolean isExternalLink(String href)
116    {
117  5103 try {
118  5103 URI uri = new URI(href);
119  5103 return uri.isAbsolute();
120    } catch (URISyntaxException e) {
121  0 return false;
122    }
123    }
124   
125    }