Merge "Clicking on CID link causes webview corruption" into ub-gmail-ur14-dev
diff --git a/src/com/android/mail/utils/HtmlSanitizer.java b/src/com/android/mail/utils/HtmlSanitizer.java
index da29345..ca831df 100644
--- a/src/com/android/mail/utils/HtmlSanitizer.java
+++ b/src/com/android/mail/utils/HtmlSanitizer.java
@@ -116,10 +116,22 @@
};
/**
- * Disallow the "mailto:" url on images so that "Show pictures" can't be used to start composing
- * a bajillion emails.
+ * Disallow "cid:" and "mailto:" urls on all tags not <a> or <img>.
*/
- private static final AttributePolicy NO_MAILTO_URL =
+ private static final AttributePolicy URL_PROTOCOLS =
+ new FilterUrlByProtocolAttributePolicy(ImmutableList.of("http", "https"));
+
+ /**
+ * Disallow the "cid:" url on links. Do allow "mailto:" urls to support sending mail.
+ */
+ private static final AttributePolicy A_HREF_PROTOCOLS =
+ new FilterUrlByProtocolAttributePolicy(ImmutableList.of("mailto", "http", "https"));
+
+ /**
+ * Disallow the "mailto:" url on images so that "Show pictures" can't be used to start composing
+ * a bajillion emails. Do allow "cid:" urls to support inline image attachments.
+ */
+ private static final AttributePolicy IMG_SRC_PROTOCOLS =
new FilterUrlByProtocolAttributePolicy(ImmutableList.of("cid", "http", "https"));
/**
@@ -180,17 +192,20 @@
.allowUrlProtocols("cid", "http", "https", "mailto")
.allowStyling(CssSchema.union(CssSchema.DEFAULT, ADDITIONAL_CSS))
.disallowTextIn("applet", "frameset", "object", "script", "style", "title")
- .allowElements("a").allowAttributes("coords", "href", "name", "shape").onElements("a")
+ .allowElements("a")
+ .allowAttributes("coords", "name", "shape").onElements("a")
+ .allowAttributes("href").matching(A_HREF_PROTOCOLS).onElements("a")
.allowElements("abbr").allowAttributes("title").onElements("abbr")
.allowElements("acronym").allowAttributes("title").onElements("acronym")
.allowElements("address")
.allowElements("area")
- .allowAttributes("alt", "coords", "href", "nohref", "name", "shape")
- .onElements("area")
+ .allowAttributes("alt", "coords", "nohref", "name", "shape").onElements("area")
+ .allowAttributes("href").matching(URL_PROTOCOLS).onElements("area")
.allowElements("article")
.allowElements("aside")
.allowElements("b")
- .allowElements("base").allowAttributes("href").onElements("base")
+ .allowElements("base")
+ .allowAttributes("href").matching(URL_PROTOCOLS).onElements("base")
.allowElements("bdi").allowAttributes("dir").onElements("bdi")
.allowElements("bdo").allowAttributes("dir").onElements("bdo")
.allowElements("big")
@@ -207,7 +222,7 @@
.allowElements("cite")
.allowElements("code")
.allowElements("col")
- . allowAttributes("align", "bgcolor", "char", "charoff", "span", "valign", "width")
+ .allowAttributes("align", "bgcolor", "char", "charoff", "span", "valign", "width")
.onElements("col")
.allowElements("colgroup")
.allowAttributes("align", "char", "charoff", "span", "valign", "width")
@@ -247,18 +262,23 @@
.onElements("hr")
.allowElements("i")
.allowElements("img")
+ .allowAttributes("src").matching(IMG_SRC_PROTOCOLS).onElements("img")
+ .allowAttributes("longdesc").matching(URL_PROTOCOLS).onElements("img")
.allowAttributes("align", "alt", "border", "crossorigin", "height", "hspace",
- "ismap", "longdesc", "usemap", "vspace", "width")
+ "ismap", "usemap", "vspace", "width")
.onElements("img")
- .allowAttributes("src").matching(NO_MAILTO_URL).onElements("img")
.allowElements("input")
+ .allowAttributes("src").matching(URL_PROTOCOLS).onElements("input")
+ .allowAttributes("formaction").matching(URL_PROTOCOLS).onElements("input")
.allowAttributes("accept", "align", "alt", "autocomplete", "autofocus", "checked",
- "disabled", "form", "formaction", "formenctype", "formmethod",
- "formnovalidate", "formtarget", "height", "list", "max", "maxlength", "min",
- "multiple", "name", "pattern", "placeholder", "readonly", "required",
- "size", "src", "step", "type", "value", "width")
+ "disabled", "form", "formenctype", "formmethod", "formnovalidate",
+ "formtarget", "height", "list", "max", "maxlength", "min", "multiple",
+ "name", "pattern", "placeholder", "readonly", "required", "size", "step",
+ "type", "value", "width")
.onElements("input")
- .allowElements("ins").allowAttributes("cite", "datetime").onElements("ins")
+ .allowElements("ins")
+ .allowAttributes("cite").matching(URL_PROTOCOLS).onElements("ins")
+ .allowAttributes("datetime").onElements("ins")
.allowElements("kbd")
.allowElements("keygen")
.allowAttributes("autofocus", "challenge", "disabled", "form", "keytype", "name")
@@ -271,9 +291,9 @@
.allowElements("mark")
.allowElements("menu").allowAttributes("label", "type").onElements("menu")
.allowElements("menuitem")
- .allowAttributes("checked", "command", "default", "disabled", "icon", "label",
- "type", "radiogroup")
- .onElements("menuitem")
+ .allowAttributes("icon").matching(URL_PROTOCOLS).onElements("menuitem")
+ .allowAttributes("checked", "command", "default", "disabled", "label", "type",
+ "radiogroup").onElements("menuitem")
.allowElements("meter")
.allowAttributes("form", "high", "low", "max", "min", "optimum", "value")
.onElements("meter")
@@ -289,7 +309,7 @@
.allowElements("p").allowAttributes("align").onElements("p")
.allowElements("pre").allowAttributes("width").onElements("pre")
.allowElements("progress").allowAttributes("max", "value").onElements("progress")
- .allowElements("q").allowAttributes("cite").onElements("q")
+ .allowElements("q").allowAttributes("cite").matching(URL_PROTOCOLS).onElements("q")
.allowElements("rp")
.allowElements("rt")
.allowElements("ruby")
diff --git a/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java b/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java
index 578ce4a..0e5715b 100644
--- a/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java
+++ b/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java
@@ -73,7 +73,9 @@
}
/**
- * Technically, RFC 2392 doesn't limit where CID urls may appear; they are accepted everywhere.
+ * Technically, RFC 2392 doesn't limit where CID urls may appear. But, Webview is unhappy
+ * handling them within link tags, so we only allow them in img src attributes until we see a
+ * reason to expand their acceptance.
*/
public void testCIDurls() {
sanitize("<img src=\"http://www.here.com/awesome.png\"/>",
@@ -87,8 +89,7 @@
"<a href=\"http://www.here.com/awesome.png\"></a>");
sanitize("<a href=\"https://www.here.com/awesome.png\"/>",
"<a href=\"https://www.here.com/awesome.png\"></a>");
- sanitize("<a href=\"cid:ii_145bda161daf6f9c\"/>",
- "<a href=\"cid:ii_145bda161daf6f9c\"></a>");
+ sanitize("<a href=\"cid:ii_145bda161daf6f9c\"/>", "");
}
// todo the stock CssSchema in OWASP does NOT allow the float property; I experiment with adding
diff --git a/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java b/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java
index 1da1ce0..5916162 100644
--- a/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java
+++ b/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java
@@ -21,6 +21,7 @@
// allowed attributes
sanitize("<a coords=\"something\"></a>", "<a coords=\"something\"></a>");
sanitize("<a href=\"http://www.here.com\"></a>", "<a href=\"http://www.here.com\"></a>");
+ sanitize("<a href=\"https://www.here.com\"></a>", "<a href=\"https://www.here.com\"></a>");
sanitize("<a name=\"something\"></a>", "<a name=\"something\"></a>");
sanitize("<a shape=\"something\"></a>", "<a shape=\"something\"></a>");
@@ -30,6 +31,7 @@
sanitize("<a datasrc=\"something\"></a>", "");
sanitize("<a download=\"something\"></a>", "");
sanitize("<a href=\"javascript:badness()\"></a>", "");
+ sanitize("<a href=\"cid:ii_hyw5v8ej0\"></a>", "");
sanitize("<a hreflang=\"something\"></a>", "");
sanitize("<a media=\"something\"></a>", "");
sanitize("<a methods=\"something\"></a>", "");
@@ -70,6 +72,7 @@
sanitize("<area alt=\"something\"/>", "<area alt=\"something\" />");
sanitize("<area coords=\"something\"/>", "<area coords=\"something\" />");
sanitize("<area href=\"http://www.here.com\"/>", "<area href=\"http://www.here.com\" />");
+ sanitize("<area href=\"https://www.here.com\"/>", "<area href=\"https://www.here.com\" />");
sanitize("<area name=\"something\"/>", "<area name=\"something\" />");
sanitize("<area nohref />", "<area nohref=\"nohref\" />");
sanitize("<area shape=\"something\"/>", "<area shape=\"something\" />");
@@ -78,6 +81,7 @@
sanitize("<area accessKey=\"A\"/>", "<area />");
sanitize("<area download=\"something\"/>", "<area />");
sanitize("<area href=\"javascript:badness()\"/>", "<area />");
+ sanitize("<area href=\"cid:ii_hyw5v8ej0\"/>", "<area />");
sanitize("<area hreflang=\"something\"/>", "<area />");
sanitize("<area media=\"something\"/>", "<area />");
sanitize("<area rel=\"something\"/>", "<area />");
@@ -106,10 +110,13 @@
// allowed attributes
sanitize("<base href=\"http://www.example.com/\">",
"<base href=\"http://www.example.com/\" />");
+ sanitize("<base href=\"https://www.example.com/\">",
+ "<base href=\"https://www.example.com/\" />");
// disallowed attributes
sanitize("<base target=\"_blank\">", "<base />");
sanitize("<base href=\"javascript:badness()\">", "<base />");
+ sanitize("<base href=\"cid:ii_hyw5v8ej0\">", "<base />");
sanitize("<base href=\"javascript:alert('XSS');//\">", "<base />");
}
@@ -485,11 +492,18 @@
sanitize("<img width=\"22\"/>", "<img width=\"22\" />");
sanitize("<img src=\"http://www.overhere.com/\"></img>",
"<img src=\"http://www.overhere.com/\" />");
+ sanitize("<img src=\"https://www.overhere.com/\"></img>",
+ "<img src=\"https://www.overhere.com/\" />");
+ sanitize("<img src=\"cid:ii_hyw5v8ej0\"></img>",
+ "<img src=\"cid:ii_hyw5v8ej0\" />");
sanitize("<img longdesc=\"http://www.overhere.com/\"></img>",
"<img longdesc=\"http://www.overhere.com/\" />");
+ sanitize("<img longdesc=\"https://www.overhere.com/\"></img>",
+ "<img longdesc=\"https://www.overhere.com/\" />");
sanitize("<img src=\"javascript:badness()\"></img>", "");
sanitize("<img longdesc=\"javascript:badness()\"></img>", "");
+ sanitize("<img longdesc=\"cid:ii_hyw5v8ej0\"></img>", "");
sanitize("<img src=javascript:alert('XSS')>", "");
sanitize("<img src=JaVaScRiPt:alert('XSS')>", "");
sanitize("<img src=javascript:alert(\"XSS\")>", "");
@@ -555,10 +569,16 @@
sanitize("<input width=\"50\"/>", "<input width=\"50\" />");
sanitize("<input src=\"http://www.overhere.com/\"></input>",
"<input src=\"http://www.overhere.com/\" />");
+ sanitize("<input src=\"https://www.overhere.com/\"></input>",
+ "<input src=\"https://www.overhere.com/\" />");
sanitize("<input formaction=\"http://www.overhere.com/\"></input>",
"<input formaction=\"http://www.overhere.com/\" />");
+ sanitize("<input formaction=\"https://www.overhere.com/\"></input>",
+ "<input formaction=\"https://www.overhere.com/\" />");
+ sanitize("<input src=\"cid:ii_hyw5v8ej0\"></input>", "");
sanitize("<input src=\"javascript:badness()\"></input>", "");
+ sanitize("<input formaction=\"cid:ii_hyw5v8ej0\"></input>", "");
sanitize("<input formaction=\"javascript:badness()\"></input>", "");
sanitize("<input type=\"image\" src=\"javascript:alert('XSS');\">",
"<input type=\"image\" />");
@@ -575,8 +595,13 @@
sanitize("<ins cite=\"javascript:badness();\">something</ins>", "<ins>something</ins>");
sanitize("<ins cite=\"http://www.reason.com/\">something</ins>",
"<ins cite=\"http://www.reason.com/\">something</ins>");
+ sanitize("<ins cite=\"https://www.reason.com/\">something</ins>",
+ "<ins cite=\"https://www.reason.com/\">something</ins>");
sanitize("<ins datetime=\"something\">something</ins>",
"<ins datetime=\"something\">something</ins>");
+
+ sanitize("<ins cite=\"cid:ii_hyw5v8ej0\">something</ins>",
+ "<ins>something</ins>");
}
public void testKbd() {
@@ -614,6 +639,8 @@
public void testLink() {
sanitize("<link charset=\"utf8\"/>", "");
sanitize("<link href=\"http://www.reason.com/\"/>", "");
+ sanitize("<link href=\"https://www.reason.com/\"/>", "");
+ sanitize("<link href=\"cid:ii_hyw5v8ej0\"/>", "");
sanitize("<link hreflang=\"fr_CA\"/>", "");
sanitize("<link media=\"tv\"/>", "");
sanitize("<link rel=\"alternate\"/>", "");
@@ -655,6 +682,8 @@
"<menuitem disabled=\"disabled\"></menuitem>");
sanitize("<menuitem icon=\"http://www.reason.com/\"></menuitem>",
"<menuitem icon=\"http://www.reason.com/\"></menuitem>");
+ sanitize("<menuitem icon=\"https://www.reason.com/\"></menuitem>",
+ "<menuitem icon=\"https://www.reason.com/\"></menuitem>");
sanitize("<menuitem label=\"something\"></menuitem>",
"<menuitem label=\"something\"></menuitem>");
sanitize("<menuitem type=\"checkbox\"></menuitem>",
@@ -662,6 +691,7 @@
sanitize("<menuitem radiogroup=\"something\"></menuitem>",
"<menuitem radiogroup=\"something\"></menuitem>");
+ sanitize("<menuitem icon=\"cid:ii_hyw5v8ej0\"></menuitem>", "<menuitem></menuitem>");
sanitize("<menuitem icon=\"javascript:badness()\"></menuitem>", "<menuitem></menuitem>");
}
@@ -773,6 +803,10 @@
sanitize("<q>something</q>", "<q>something</q>");
sanitize("<q cite=\"http://www.reason.com/\">something</q>",
"<q cite=\"http://www.reason.com/\">something</q>");
+ sanitize("<q cite=\"https://www.reason.com/\">something</q>",
+ "<q cite=\"https://www.reason.com/\">something</q>");
+
+ sanitize("<q cite=\"cid:ii_hyw5v8ej0\">something</q>", "<q>something</q>");
sanitize("<q cite=\"javascript:badness()\">something</q>", "<q>something</q>");
}