aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2016-08-28 18:38:15 +0300
committerGravatar Vitaly Takmazov2016-08-28 18:38:15 +0300
commit14f111c2e3f20f563dfbe17181f77bfaa9cd57ef (patch)
tree6ed744340e137f1112642182e41cbcb8ed030afe
parent7092b70a8a92fc1fdfaa8a2c54ec7a2037f8790c (diff)
Tags: should be escaped in db and unescaped in templates
-rw-r--r--build.gradle1
-rw-r--r--juick-core/src/main/java/com/juick/server/MessagesQueries.java3
-rw-r--r--juick-core/src/main/java/com/juick/server/TagQueries.java14
-rw-r--r--juick-www/src/main/java/com/juick/www/Discover.java3
-rw-r--r--juick-www/src/main/java/com/juick/www/Home.java3
-rw-r--r--juick-www/src/main/java/com/juick/www/NewMessage.java7
-rw-r--r--juick-www/src/main/java/com/juick/www/PageTemplates.java27
-rw-r--r--juick-www/src/main/java/com/juick/www/User.java9
-rw-r--r--juick-www/src/main/java/com/juick/www/Utils.java4
-rw-r--r--src/test/java/com/juick/tests/ApiTests.java11
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("<", "&lt;").replaceAll(">", "&gt;");
+ 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("<", "&lt;");
- tag = tag.replaceAll(">", "&gt;");
- 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("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("'", "&apos;").replaceAll("\"", "&quot;").replaceAll("\n", "&#10;");
- }
-
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\">&gt;_&lt;</a>", PageTemplates.formatTags(new ArrayList<Tag>() {{ add(htmlTag); }} ));
}
@Test