diff options
author | Vitaly Takmazov | 2016-08-28 18:38:15 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2016-08-28 18:38:15 +0300 |
commit | 14f111c2e3f20f563dfbe17181f77bfaa9cd57ef (patch) | |
tree | 6ed744340e137f1112642182e41cbcb8ed030afe | |
parent | 7092b70a8a92fc1fdfaa8a2c54ec7a2037f8790c (diff) |
Tags: should be escaped in db and unescaped in templates
-rw-r--r-- | build.gradle | 1 | ||||
-rw-r--r-- | juick-core/src/main/java/com/juick/server/MessagesQueries.java | 3 | ||||
-rw-r--r-- | juick-core/src/main/java/com/juick/server/TagQueries.java | 14 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/Discover.java | 3 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/Home.java | 3 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/NewMessage.java | 7 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/PageTemplates.java | 27 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/User.java | 9 | ||||
-rw-r--r-- | juick-www/src/main/java/com/juick/www/Utils.java | 4 | ||||
-rw-r--r-- | src/test/java/com/juick/tests/ApiTests.java | 11 |
10 files changed, 38 insertions, 44 deletions
diff --git a/build.gradle b/build.gradle index 7c1b7ece..25bcb550 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ repositories { } dependencies { testCompile project(':juick-core') + testCompile project(':juick-www') testCompile 'com.fasterxml.jackson.core:jackson-core:2.8.1' testCompile 'com.fasterxml.jackson.core:jackson-databind:2.8.1' testCompile 'org.springframework:spring-jdbc:4.3.2.RELEASE' diff --git a/juick-core/src/main/java/com/juick/server/MessagesQueries.java b/juick-core/src/main/java/com/juick/server/MessagesQueries.java index 8c79bfd9..fa8881f3 100644 --- a/juick-core/src/main/java/com/juick/server/MessagesQueries.java +++ b/juick-core/src/main/java/com/juick/server/MessagesQueries.java @@ -21,6 +21,7 @@ import com.juick.Message; import com.juick.Tag; import com.juick.User; import com.juick.server.helpers.PrivacyOpts; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.ConnectionCallback; @@ -302,7 +303,7 @@ public class MessagesQueries { return sql.query("SELECT tags.tag_id,synonym_id,name,stat_messages FROM tags " + "INNER JOIN messages_tags ON (messages_tags.message_id=? AND messages_tags.tag_id=tags.tag_id)", new Object[]{mid}, (rs, num) -> { - com.juick.Tag t = new com.juick.Tag(rs.getString(3)); + com.juick.Tag t = new com.juick.Tag(StringEscapeUtils.unescapeHtml4(rs.getString(3))); t.TID = rs.getInt(1); t.SynonymID = rs.getInt(2); t.UsageCnt = rs.getInt(4); diff --git a/juick-core/src/main/java/com/juick/server/TagQueries.java b/juick-core/src/main/java/com/juick/server/TagQueries.java index 76c12425..0e3c0c06 100644 --- a/juick-core/src/main/java/com/juick/server/TagQueries.java +++ b/juick-core/src/main/java/com/juick/server/TagQueries.java @@ -18,6 +18,7 @@ package com.juick.server; import com.juick.Tag; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; @@ -42,7 +43,7 @@ public class TagQueries { try { return sql.queryForObject("SELECT synonym_id,name FROM tags WHERE tag_id=?", (rs, num) -> { - Tag ret = new Tag(rs.getString(2)); + Tag ret = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(2))); ret.TID = tid; ret.SynonymID = rs.getInt(1); return ret; @@ -57,11 +58,11 @@ public class TagQueries { try { ret = sql.queryForObject("SELECT tag_id,synonym_id,name FROM tags WHERE name=?", (rs, rowNum) -> { - Tag ret1 = new Tag(rs.getString(3)); + Tag ret1 = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(3))); ret1.TID = rs.getInt(1); ret1.SynonymID = rs.getInt(2); return ret1; - }, tag); + }, StringEscapeUtils.escapeHtml4(tag)); } catch (EmptyResultDataAccessException e) { // tag not found } @@ -101,7 +102,7 @@ public class TagQueries { sql.update(con -> { PreparedStatement stmt = con.prepareStatement("INSERT INTO tags(name) VALUES (?)", Statement.RETURN_GENERATED_KEYS); - stmt.setString(1, name); + stmt.setString(1, StringEscapeUtils.escapeHtml4(name)); return stmt; }, holder); @@ -114,7 +115,7 @@ public class TagQueries { "AND messages.message_id=messages_tags.message_id)) " + "INNER JOIN tags ON messages_tags.tag_id=tags.tag_id GROUP BY tags.tag_id ORDER BY tags.name ASC", (rs, rowNum) -> { - Tag t = new Tag(rs.getString(1)); + Tag t = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(1))); t.UsageCnt = rs.getInt(2); return t; }, uid); @@ -127,7 +128,8 @@ public class TagQueries { } public static List<String> getPopularTags(JdbcTemplate sql) { - return sql.queryForList("SELECT name FROM tags WHERE top=1 ORDER BY name ASC", String.class); + return sql.queryForList("SELECT name FROM tags WHERE top=1 ORDER BY name ASC", String.class).stream() + .map(StringEscapeUtils::unescapeHtml4).collect(Collectors.toList()); } public static List<Tag> updateTags(JdbcTemplate sql, int mid, List<Tag> newTags) { List<Tag> currentTags = MessagesQueries.getMessageTags(sql, mid); diff --git a/juick-www/src/main/java/com/juick/www/Discover.java b/juick-www/src/main/java/com/juick/www/Discover.java index 1954aac9..4fd8c3b6 100644 --- a/juick-www/src/main/java/com/juick/www/Discover.java +++ b/juick-www/src/main/java/com/juick/www/Discover.java @@ -20,6 +20,7 @@ package com.juick.www; import com.juick.server.AdsQueries; import com.juick.server.MessagesQueries; import com.juick.server.TagQueries; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.jdbc.core.JdbcTemplate; import javax.servlet.ServletException; @@ -73,7 +74,7 @@ public class Discover { int visitor_uid = visitor.getUID(); - String title = "*" + Utils.encodeHTML(paramTag.getName()); + String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName()); List<Integer> mids = MessagesQueries.getTag(sql, paramTag.TID, visitor_uid, paramBefore, (visitor_uid == 0) ? 40 : 20); response.setContentType("text/html; charset=UTF-8"); diff --git a/juick-www/src/main/java/com/juick/www/Home.java b/juick-www/src/main/java/com/juick/www/Home.java index e11ed6f4..462c47bb 100644 --- a/juick-www/src/main/java/com/juick/www/Home.java +++ b/juick-www/src/main/java/com/juick/www/Home.java @@ -19,6 +19,7 @@ package com.juick.www; import com.juick.server.AdsQueries; import com.juick.server.MessagesQueries; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.jdbc.core.JdbcTemplate; import javax.servlet.ServletException; @@ -55,7 +56,7 @@ public class Home { String paramShow = request.getParameter("show"); if (paramSearch != null) { - title = "Поиск: " + Utils.encodeHTML(paramSearch); + title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch); mids = MessagesQueries.getSearch(sql, sqlSearch, Utils.encodeSphinx(paramSearch), paramBefore); } else if (paramShow == null) { if (visitor.getUID() > 0) { diff --git a/juick-www/src/main/java/com/juick/www/NewMessage.java b/juick-www/src/main/java/com/juick/www/NewMessage.java index 56fe99cb..d45f1a4b 100644 --- a/juick-www/src/main/java/com/juick/www/NewMessage.java +++ b/juick-www/src/main/java/com/juick/www/NewMessage.java @@ -27,6 +27,7 @@ import com.juick.xmpp.extensions.JuickUser; import com.juick.xmpp.extensions.Nickname; import com.juick.xmpp.extensions.XOOB; import net.coobird.thumbnailator.Thumbnails; +import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.math.NumberUtils; import org.springframework.jdbc.core.JdbcTemplate; @@ -83,7 +84,7 @@ public class NewMessage { if (body.length() > 4096) { body = body.substring(0, 4096); } - body = Utils.encodeHTML(body); + body = StringEscapeUtils.escapeHtml4(body); } out.println("<p><textarea name=\"body\" class=\"newmessage\" rows=\"7\" cols=\"10\">" + body + "</textarea><br/>"); @@ -126,9 +127,9 @@ public class NewMessage { } String taglink = ""; try { - taglink = "<a onclick=\"return addTag('" + Utils.encodeHTML(tags.get(i).getName()) + "')\" href=\"/" + + taglink = "<a onclick=\"return addTag('" + StringEscapeUtils.escapeHtml4(tags.get(i).getName()) + "')\" href=\"/" + visitor.getUName() + "/?tag=" + URLEncoder.encode(tags.get(i).getName(), "utf-8") + - "\" title=\"" + tags.get(i).UsageCnt + "\">" + Utils.encodeHTML(tags.get(i).getName()) + "</a>"; + "\" title=\"" + tags.get(i).UsageCnt + "\">" + StringEscapeUtils.escapeHtml4(tags.get(i).getName()) + "</a>"; } catch (UnsupportedEncodingException e) { } int usagecnt = tags.get(i).UsageCnt; diff --git a/juick-www/src/main/java/com/juick/www/PageTemplates.java b/juick-www/src/main/java/com/juick/www/PageTemplates.java index be9a024c..5715acd3 100644 --- a/juick-www/src/main/java/com/juick/www/PageTemplates.java +++ b/juick-www/src/main/java/com/juick/www/PageTemplates.java @@ -22,6 +22,7 @@ import com.juick.Tag; import com.juick.server.MessagesQueries; import com.juick.server.TagQueries; import com.juick.server.UserQueries; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.StringUtils; import ru.sape.Sape; @@ -89,7 +90,7 @@ public class PageTemplates { out.println("</ul></nav>"); out.print(" <div id=\"search\"><form action=\"/\"><input type=\"text\" name=\"search\" class=\"text\" placeholder=\"Поиск\""); if (search != null) { - out.print(" value=\"" + Utils.encodeHTML(search) + "\""); + out.print(" value=\"" + StringEscapeUtils.escapeHtml4(search) + "\""); } out.println("/></form></div>"); out.println(" <section id=\"headdiv\">"); @@ -135,7 +136,7 @@ public class PageTemplates { public static String formatPopularTags(JdbcTemplate sql, int cnt) { List<String> popularTags = TagQueries.getPopularTags(sql).stream() - .map(t -> "<a href=\"/tag/" + URLEncoder.encode(t) + "\">" + Utils.encodeHTML(t) + "</a>").collect(Collectors.toList()); + .map(t -> "<a href=\"/tag/" + URLEncoder.encode(t) + "\">" + StringEscapeUtils.escapeHtml4(t) + "</a>").collect(Collectors.toList()); return StringUtils.collectionToDelimitedString(popularTags, " "); } @@ -188,7 +189,7 @@ public class PageTemplates { public static String formatTags(List<Tag> tags) { String ret = ""; for (Tag tag : tags) { - String tagName = tag.getName().replaceAll("<", "<").replaceAll(">", ">"); + String tagName = StringEscapeUtils.escapeHtml4(tag.getName()); try { ret += " *<a href=\"/tag/" + URLEncoder.encode(tag.getName(), "utf-8") + "\""; if (tag.UsageCnt < 2) { @@ -202,26 +203,6 @@ public class PageTemplates { return ret; } - public static String formatTags(List<String> tags, com.juick.User user) { - String ret = ""; - for (String tag : tags) { - tag = tag.replaceAll("<", "<"); - tag = tag.replaceAll(">", ">"); - try { - ret += " *<a href=\""; - if (user == null) { - ret += "/tag/"; - } else { - ret += "/" + user.getUName() + "/?tag="; - } - ret += URLEncoder.encode(tag, "utf-8") + "\">" + tag + "</a>"; - } catch (UnsupportedEncodingException e) { - } - } - - return ret; - } - public static String formatDate(int minutes, Date fulldate) { if (minutes < 1) { return "сейчас"; diff --git a/juick-www/src/main/java/com/juick/www/User.java b/juick-www/src/main/java/com/juick/www/User.java index 29218d0a..967d06c7 100644 --- a/juick-www/src/main/java/com/juick/www/User.java +++ b/juick-www/src/main/java/com/juick/www/User.java @@ -21,6 +21,7 @@ import com.juick.Tag; import com.juick.server.MessagesQueries; import com.juick.server.TagQueries; import com.juick.server.UserQueries; +import org.apache.commons.lang3.StringEscapeUtils; import org.springframework.jdbc.core.JdbcTemplate; import javax.servlet.ServletException; @@ -89,10 +90,10 @@ public class User { String title; if (paramShow == null) { if (paramTag != null) { - title = "Блог " + user.getUName() + ": *" + Utils.encodeHTML(paramTag.getName()); + title = "Блог " + user.getUName() + ": *" + StringEscapeUtils.escapeHtml4(paramTag.getName()); mids = MessagesQueries.getUserTag(sql, user.getUID(), paramTag.TID, privacy, paramBefore); } else if (paramSearch != null) { - title = "Блог " + user.getUName() + ": " + Utils.encodeHTML(paramSearch); + title = "Блог " + user.getUName() + ": " + StringEscapeUtils.escapeHtml4(paramSearch); mids = MessagesQueries.getUserSearch(sql, sqlSearch, user.getUID(), Utils.encodeSphinx(paramSearch), privacy, paramBefore); } else { title = "Блог " + user.getUName(); @@ -132,7 +133,7 @@ public class User { if (paramTag != null) { out.println("<p class=\"page\"><a href=\"/tag/" + URLEncoder.encode(paramTag.getName(), "UTF-8") + "\">← Все записи с тегом <b>" + - Utils.encodeHTML(paramTag.getName()) + "</b></a></p>"); + StringEscapeUtils.escapeHtml4(paramTag.getName()) + "</b></a></p>"); } PageTemplates.printMessages(out, sql, user, mids, visitor, visitor.getUID() == 0 ? 4 : 5, 0); @@ -328,7 +329,7 @@ public class User { String ret = ""; int count = cnt > 0 ? Math.min(tags.size(), cnt) : tags.size(); for (int i = 0; i < count; i++) { - String tag = Utils.encodeHTML(tags.get(i).getName()); + String tag = StringEscapeUtils.escapeHtml4(tags.get(i).getName()); try { tag = "<a href=\"./?tag=" + URLEncoder.encode(tags.get(i).getName(), "UTF-8") + "\" title=\"" + tags.get(i).UsageCnt + "\" rel=\"nofollow\">" + tag + "</a>"; diff --git a/juick-www/src/main/java/com/juick/www/Utils.java b/juick-www/src/main/java/com/juick/www/Utils.java index 24f78a1c..26e938a7 100644 --- a/juick-www/src/main/java/com/juick/www/Utils.java +++ b/juick-www/src/main/java/com/juick/www/Utils.java @@ -130,10 +130,6 @@ public class Utils { } } - public static String encodeHTML(String str) { - return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("'", "'").replaceAll("\"", """).replaceAll("\n", " "); - } - public static String encodeSphinx(String str) { return str.replaceAll("@", "\\\\@"); } diff --git a/src/test/java/com/juick/tests/ApiTests.java b/src/test/java/com/juick/tests/ApiTests.java index 0d34bfbb..b5632b39 100644 --- a/src/test/java/com/juick/tests/ApiTests.java +++ b/src/test/java/com/juick/tests/ApiTests.java @@ -12,6 +12,8 @@ import com.juick.server.TagQueries; import com.juick.server.UserQueries; import com.juick.server.protocol.JuickProtocol; import com.juick.server.protocol.ProtocolReply; +import com.juick.www.PageTemplates; +import org.apache.commons.lang3.StringEscapeUtils; import org.json.JSONArray; import org.junit.After; import org.junit.Before; @@ -36,7 +38,7 @@ public class ApiTests { DB db; @Before public void setupConnection() throws ManagedProcessException { - db = DB.newEmbeddedDB(3306); + db = DB.newEmbeddedDB(33306); db.start(); db.createDB("juick"); db.source("schema.sql"); @@ -88,6 +90,13 @@ public class ApiTests { assertEquals(1, SubscriptionsQueries.getUsersSubscribedToComments(jdbc, msg.getMID(), user.getUID()).size()); MessagesQueries.deleteMessage(jdbc, user_id, mid); MessagesQueries.deleteMessage(jdbc, user_id, mid2); + String htmlTagName = ">_<"; + Tag htmlTag = TagQueries.getTag(jdbc, htmlTagName, true); + String dbTagName = jdbc.queryForObject("select name from tags where name=?", String.class, StringEscapeUtils.escapeHtml4(htmlTagName)); + assertNotEquals("db tags should be escaped", dbTagName, htmlTag.getName()); + assertEquals("object tags should unescaped", htmlTag.getName(), StringEscapeUtils.unescapeHtml4(dbTagName)); + assertEquals("template should encode escaped tag in url and show escaped tag in name", + " *<a href=\"/tag/%3E_%3C\" rel=\"nofollow\">>_<</a>", PageTemplates.formatTags(new ArrayList<Tag>() {{ add(htmlTag); }} )); } @Test |