Mentions are expanded in rendered Essay. Page title reflects Essay title.

This commit is contained in:
moandji.ezana 2012-11-29 00:01:45 +02:00
parent ca02af4ea1
commit f0152093e7
14 changed files with 151 additions and 56 deletions

View file

@ -82,7 +82,7 @@
<dependency> <dependency>
<groupId>owasp-java-html-sanitizer</groupId> <groupId>owasp-java-html-sanitizer</groupId>
<artifactId>owasp-java-html-sanitizer</artifactId> <artifactId>owasp-java-html-sanitizer</artifactId>
<version>r117</version> <version>r129</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
@ -143,5 +143,10 @@
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>13.0.1</version> <version>13.0.1</version>
</dependency> </dependency>
<dependency>
<groupId>com.moandjiezana.tent</groupId>
<artifactId>tent-text</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -64,7 +64,7 @@ public class EssayServlet extends HttpServlet {
Post post = tentClient.getPost(essayId); Post post = tentClient.getPost(essayId);
EssayistPostContent essayContent = post.getContentAs(EssayistPostContent.class); EssayistPostContent essayContent = post.getContentAs(EssayistPostContent.class);
essayContent.setBody(csrf.stripScripts(essayContent.getBody())); essayContent.setBody(csrf.permissive(essayContent.getBody()));
EssayPage essayPage = templates.essay(); EssayPage essayPage = templates.essay();
if (user.owns(post)) { if (user.owns(post)) {

View file

@ -6,6 +6,7 @@ import com.moandjiezana.tent.client.posts.PostQuery;
import com.moandjiezana.tent.client.posts.content.EssayContent; import com.moandjiezana.tent.client.posts.content.EssayContent;
import com.moandjiezana.tent.client.users.Permissions; import com.moandjiezana.tent.client.users.Permissions;
import com.moandjiezana.tent.essayist.tent.Entities; import com.moandjiezana.tent.essayist.tent.Entities;
import com.moandjiezana.tent.essayist.text.TextTransformation;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -18,18 +19,18 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.pegdown.PegDownProcessor;
@Singleton @Singleton
public class EssaysServlet extends HttpServlet { public class EssaysServlet extends HttpServlet {
private Templates templates; private Templates templates;
private Users users; private Users users;
private Provider<EssayistSession> sessions; private Provider<EssayistSession> sessions;
private TextTransformation textTransformation;
@Inject @Inject
public EssaysServlet(Users users, Templates templates, Provider<EssayistSession> sessions) { public EssaysServlet(Users users, TextTransformation textTransformation, Templates templates, Provider<EssayistSession> sessions) {
this.users = users; this.users = users;
this.textTransformation = textTransformation;
this.templates = templates; this.templates = templates;
this.sessions = sessions; this.sessions = sessions;
} }
@ -62,7 +63,7 @@ public class EssaysServlet extends HttpServlet {
post.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" }); post.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" });
EssayContent essay = new EssayContent(); EssayContent essay = new EssayContent();
essay.setTitle(req.getParameter("title")); essay.setTitle(req.getParameter("title"));
essay.setBody(new PegDownProcessor().markdownToHtml(req.getParameter("body"))); essay.setBody(textTransformation.transformEssay(req.getParameter("body")));
essay.setExcerpt(req.getParameter("excerpt")); essay.setExcerpt(req.getParameter("excerpt"));
post.setContent(essay); post.setContent(essay);

View file

@ -2,7 +2,7 @@ package com.moandjiezana.tent.essayist;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
import com.moandjiezana.tent.essayist.auth.Authenticated; import com.moandjiezana.tent.essayist.auth.Authenticated;
import com.moandjiezana.tent.essayist.security.Csrf; import com.moandjiezana.tent.essayist.text.TextTransformation;
import java.io.IOException; import java.io.IOException;
@ -13,25 +13,22 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.pegdown.PegDownProcessor;
@Singleton @Singleton
@Authenticated @Authenticated
public class PreviewServlet extends HttpServlet { public class PreviewServlet extends HttpServlet {
private final Csrf csrf; private final TextTransformation textTransformation;
@Inject @Inject
public PreviewServlet(Csrf csrf) { public PreviewServlet(TextTransformation textTransformation) {
this.csrf = csrf; this.textTransformation = textTransformation;
} }
@Override @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String body = CharStreams.toString(req.getReader()); String body = CharStreams.toString(req.getReader());
String html = new PegDownProcessor().markdownToHtml(body); String essay = textTransformation.transformEssay(body);
String sanitized = csrf.stripScripts(html);
resp.getWriter().write(sanitized); resp.getWriter().write(essay);
} }
} }

View file

@ -11,6 +11,7 @@ import com.moandjiezana.tent.client.users.Permissions;
import com.moandjiezana.tent.essayist.auth.Authenticated; import com.moandjiezana.tent.essayist.auth.Authenticated;
import com.moandjiezana.tent.essayist.config.Routes; import com.moandjiezana.tent.essayist.config.Routes;
import com.moandjiezana.tent.essayist.tent.Entities; import com.moandjiezana.tent.essayist.tent.Entities;
import com.moandjiezana.tent.essayist.text.TextTransformation;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -23,8 +24,6 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.pegdown.PegDownProcessor;
@Singleton @Singleton
@Authenticated @Authenticated
public class WriteServlet extends HttpServlet { public class WriteServlet extends HttpServlet {
@ -33,9 +32,11 @@ public class WriteServlet extends HttpServlet {
private Provider<EssayistSession> sessions; private Provider<EssayistSession> sessions;
private Tasks tasks; private Tasks tasks;
private Provider<Routes> routes; private Provider<Routes> routes;
private TextTransformation textTransformation;
@Inject @Inject
public WriteServlet(Provider<EssayistSession> sessions, Templates templates, Provider<Routes> routes, Tasks tasks) { public WriteServlet(TextTransformation textTransformation, Provider<EssayistSession> sessions, Templates templates, Provider<Routes> routes, Tasks tasks) {
this.textTransformation = textTransformation;
this.sessions = sessions; this.sessions = sessions;
this.templates = templates; this.templates = templates;
this.routes = routes; this.routes = routes;
@ -71,7 +72,7 @@ public class WriteServlet extends HttpServlet {
EssayContent essay = new EssayContent(); EssayContent essay = new EssayContent();
essay.setTitle(req.getParameter("title")); essay.setTitle(req.getParameter("title"));
final String body = req.getParameter("body"); final String body = req.getParameter("body");
essay.setBody(new PegDownProcessor().markdownToHtml(body)); essay.setBody(textTransformation.transformEssay(body));
essay.setExcerpt(req.getParameter("excerpt")); essay.setExcerpt(req.getParameter("excerpt"));
post.setContent(essay); post.setContent(essay);
@ -89,27 +90,11 @@ public class WriteServlet extends HttpServlet {
tentClient.write(metadataPost); tentClient.write(metadataPost);
resp.sendRedirect(req.getContextPath() + "/" + Entities.getForUrl(tentClient.getProfile().getCore().getEntity()) + "/essay/" + newPost.getId()); resp.sendRedirect(req.getContextPath() + "/" + Entities.getForUrl(tentClient.getProfile().getCore().getEntity()) + "/essay/" + newPost.getId());
// tasks.run(new Runnable() {
// @Override
// public void run() {
// } else {
// Post originalPost = posts.get(0);
//
// Post newPost = newPost();
//
// EssayistMetadataContent content = originalPost.getContentAs(EssayistMetadataContent.class);
// content.setRaw(body);
// }
//
// }
// });
} }
@Override @Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
TentClient tentClient = newTentClient(); TentClient tentClient = newTentClient();
// List<Post> posts = tentClient.getPosts(new PostQuery().mentionedPost(essayId).postTypes(EssayistMetadataContent.URI));
String essayId = req.getPathInfo().substring(1); String essayId = req.getPathInfo().substring(1);
Post post = newPost(); Post post = newPost();
@ -118,7 +103,7 @@ public class WriteServlet extends HttpServlet {
EssayContent essay = new EssayContent(); EssayContent essay = new EssayContent();
essay.setTitle(req.getParameter("title")); essay.setTitle(req.getParameter("title"));
final String body = req.getParameter("body"); final String body = req.getParameter("body");
essay.setBody(new PegDownProcessor().markdownToHtml(body)); essay.setBody(textTransformation.transformEssay(body));
essay.setExcerpt(req.getParameter("excerpt")); essay.setExcerpt(req.getParameter("excerpt"));
post.setContent(essay); post.setContent(essay);

View file

@ -5,6 +5,7 @@ import com.moandjiezana.tent.client.users.Profile;
import com.moandjiezana.tent.essayist.EssayistSession; import com.moandjiezana.tent.essayist.EssayistSession;
import com.moandjiezana.tent.essayist.User; import com.moandjiezana.tent.essayist.User;
import com.moandjiezana.tent.essayist.security.Csrf; import com.moandjiezana.tent.essayist.security.Csrf;
import com.moandjiezana.tent.essayist.text.TextTransformation;
import javax.inject.Inject; import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -16,14 +17,16 @@ public class JamonContext {
public final String contextPath; public final String contextPath;
public final Routes routes; public final Routes routes;
public final Csrf csrf = new Csrf(); public final Csrf csrf = new Csrf();
public final TextTransformation textTransformation;
private final HttpServletRequest req; private final HttpServletRequest req;
public final String currentUrl; public final String currentUrl;
private final EssayistSession session; private final EssayistSession session;
@Inject @Inject
public JamonContext(EssayistSession session, Routes routes, HttpServletRequest req) { public JamonContext(EssayistSession session, TextTransformation textTransformation, Routes routes, HttpServletRequest req) {
this.session = session; this.session = session;
this.textTransformation = textTransformation;
this.routes = routes; this.routes = routes;
this.req = req; this.req = req;
this.contextPath = req.getContextPath(); this.contextPath = req.getContextPath();

View file

@ -3,6 +3,7 @@ package com.moandjiezana.tent.essayist.security;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.owasp.html.HtmlPolicyBuilder; import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;
@Singleton @Singleton
public class Csrf { public class Csrf {
@ -13,12 +14,21 @@ public class Csrf {
.allowStandardUrlProtocols() .allowStandardUrlProtocols()
.allowStyling() .allowStyling()
.allowElements("iframe", "img", "a", "table", "thead", "tbody", "tr", "th", "td", "em") .allowElements("iframe", "img", "a", "table", "thead", "tbody", "tr", "th", "td", "em")
.allowAttributes("width", "height", "title").globally() .allowAttributes("width", "height", "title", "class").globally()
.allowAttributes("src", "frameborder", "webkitAllowFullScreen", "mozallowfullscreen", "allowFullScreen").onElements("iframe") .allowAttributes("src", "frameborder", "webkitAllowFullScreen", "mozallowfullscreen", "allowFullScreen").onElements("iframe")
.allowAttributes("src", "alt").onElements("img") .allowAttributes("src", "alt").onElements("img")
.allowAttributes("href").onElements("a"); .allowAttributes("href", "rel").onElements("a");
private final PolicyFactory restrictive = new HtmlPolicyBuilder()
.allowStandardUrlProtocols()
.allowElements("a")
.allowAttributes("href", "class", "rel").onElements("a").toFactory();
public String stripScripts(String html) { public String permissive(String html) {
return allowScripts.toFactory().sanitize(html); return allowScripts.toFactory().sanitize(html);
} }
public String restrictive(String html) {
return restrictive.sanitize(html);
}
} }

View file

@ -0,0 +1,53 @@
package com.moandjiezana.tent.essayist.text;
import com.moandjiezana.tent.essayist.security.Csrf;
import com.moandjiezana.tent.text.Autolink;
import com.moandjiezana.tent.text.Extractor.Entity;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.pegdown.PegDownProcessor;
@Singleton
public class TextTransformation {
private final Csrf csrf;
private final Autolink essayAutolink = new Autolink();
private final Autolink commentAutolink = new Autolink();
@Inject
public TextTransformation(Csrf csrf) {
this.csrf = csrf;
essayAutolink.setMentionIncludeSymbol(true);
Autolink.LinkTextModifier linkTextModifier = new Autolink.LinkTextModifier() {
@Override
public CharSequence modify(Entity entity, CharSequence text) {
if (text.charAt(0) == '^') {
return text.subSequence(1, text.length());
}
return text;
}
};
essayAutolink.setLinkTextModifier(linkTextModifier);
essayAutolink.setMentionClass("label label-inverse");
commentAutolink.setMentionIncludeSymbol(true);
commentAutolink.setLinkTextModifier(linkTextModifier);
commentAutolink.setMentionClass("label label-inverse");
}
public String transformEssay(String text) {
essayAutolink.setNoFollow(false);
String autoLinked = essayAutolink.autoLinkHashtags(essayAutolink.autoLinkMentionsAndLists(text));
String html = new PegDownProcessor().markdownToHtml(autoLinked);
String sanitized = csrf.permissive(html);
return sanitized;
}
public Object transformComment(String comment) {
return csrf.restrictive(commentAutolink.autoLink(comment));
}
}

View file

@ -19,7 +19,7 @@ final EssayContent content = essay.getContentAs(EssayContent.class);
final SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); final SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm ZZZZ"); final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm ZZZZ");
</%java> </%java>
<&| Layout; active = active &> <&| Layout; active = active; title = Entities.essayTitle(content) &>
<& partials/Essay; essay=essay; entityForUrl=Entities.getForUrl(essay.getEntity()); entityName=Entities.getName(profile); essayId=essay.getId(); formattedPublicationDate=dateFormat.format(new Date(essay.getPublishedAt() * 1000)); display=true; &> <& partials/Essay; essay=essay; entityForUrl=Entities.getForUrl(essay.getEntity()); entityName=Entities.getName(profile); essayId=essay.getId(); formattedPublicationDate=dateFormat.format(new Date(essay.getPublishedAt() * 1000)); display=true; &>
<& partials/Reactions; reactions=reactions; essay=essay; autoLoad=true; &> <& partials/Reactions; reactions=reactions; essay=essay; autoLoad=true; &>

View file

@ -8,6 +8,7 @@ com.moandjiezana.tent.essayist.config.*;
<%args> <%args>
boolean showNav = true; boolean showNav = true;
String active = null; String active = null;
String title = "Essayist";
</%args> </%args>
<%def navItem> <%def navItem>
@ -21,7 +22,7 @@ String url;
<html> <html>
<head> <head>
<title>Essayist</title> <title><% title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">

View file

@ -18,7 +18,7 @@ String formattedDate = dateTimeFormat.format(new Date(reaction.getPublishedAt()
<%if Post.Types.equalsIgnoreVersion(Post.Types.status("v0.1.0"), reaction.getType()) %> <%if Post.Types.equalsIgnoreVersion(Post.Types.status("v0.1.0"), reaction.getType()) %>
<i class="icon-comment"></i> <a href="<% reaction.getEntity() %>"><% displayEntity %></a> commented <small class="muted"><% formattedDate %></small><br/> <i class="icon-comment"></i> <a href="<% reaction.getEntity() %>"><% displayEntity %></a> commented <small class="muted"><% formattedDate %></small><br/>
<p> <p>
<% reaction.getContentAs(StatusContent.class).getText() %> <% jamonContext.textTransformation.transformComment(reaction.getContentAs(StatusContent.class).getText()) #n %>
</p> </p>
<%elseif Post.Types.equalsIgnoreVersion(Favorite.URI, reaction.getType()) %> <%elseif Post.Types.equalsIgnoreVersion(Favorite.URI, reaction.getType()) %>
<i class="icon-star"></i> Favourited by <a href="<% reaction.getEntity() %>"><% displayEntity %></a> <small class="muted"><% formattedDate %></small> <i class="icon-star"></i> Favourited by <a href="<% reaction.getEntity() %>"><% displayEntity %></a> <small class="muted"><% formattedDate %></small>

View file

@ -2,11 +2,15 @@ function initNavigation() {
var essayContainers = document.querySelectorAll("[data-essay=container]"); var essayContainers = document.querySelectorAll("[data-essay=container]");
var i; var i;
var displaySection = function (section, target) { var displaySection = function (section, target, title) {
var j; var j;
var detailDisplay = section === "essay" ? "block" : "none"; var detailDisplay = section === "essay" ? "block" : "none";
var listDisplay = section === "list" ? "block" : "none"; var listDisplay = section === "list" ? "block" : "none";
if (title !== undefined) {
document.title = title;
}
if (target !== document) { if (target !== document) {
target.querySelector("[data-essay=summary]").style.display = listDisplay; target.querySelector("[data-essay=summary]").style.display = listDisplay;
target.querySelector("[data-essay=full]").style.display = detailDisplay; target.querySelector("[data-essay=full]").style.display = detailDisplay;
@ -46,12 +50,12 @@ function initNavigation() {
} }
var scrollPosition = document.body.scrollTop; var scrollPosition = document.body.scrollTop;
displaySection("essay", event.currentTarget); displaySection("essay", event.currentTarget, event.target.text);
var reactionsContainer = container.querySelector('[data-essay="reactions"]'); var reactionsContainer = container.querySelector('[data-essay="reactions"]');
fetchReactions(reactionsContainer); fetchReactions(reactionsContainer);
history.pushState({ essayId: event.currentTarget.dataset.essayId, essayAuthor: event.currentTarget.dataset.essayAuthor, scrollPosition: scrollPosition }, "essay title", event.target.href); history.pushState({ essayId: event.currentTarget.dataset.essayId, essayAuthor: event.currentTarget.dataset.essayAuthor, essayTitle: event.target.text, scrollPosition: scrollPosition }, "essay title", event.target.href);
return false; return false;
}; };
@ -59,11 +63,10 @@ function initNavigation() {
var essayPopStateHandler = function (event) { var essayPopStateHandler = function (event) {
var essayContainer; var essayContainer;
if (window.location.href.indexOf("/essays") > -1 || window.location.href.indexOf("/global") > -1 || window.location.href.indexOf("/read") > -1) { if (window.location.href.indexOf("/essays") > -1 || window.location.href.indexOf("/global") > -1 || window.location.href.indexOf("/read") > -1) {
displaySection("list", document); displaySection("list", document, "Essayist");
window.scrollTo(0);
} else if (event.state !== null) { } else if (event.state !== null) {
essayContainer = document.querySelector("[data-essay-author=\"" + event.state.essayAuthor + "\"][data-essay-id=\"" + event.state.essayId + "\"]"); essayContainer = document.querySelector("[data-essay-author=\"" + event.state.essayAuthor + "\"][data-essay-id=\"" + event.state.essayId + "\"]");
displaySection("essay", essayContainer); displaySection("essay", essayContainer, event.state.essayTitle);
} }
}; };

View file

@ -8,14 +8,14 @@ public class CsrfTest {
@Test @Test
public void should_remove_external_scripts() { public void should_remove_external_scripts() {
String sanitized = new Csrf().stripScripts("<h1>title</h1><script src=\"other.js\"></script><h3>sub-title</h3><div>Some text</div><p>Some more text</p>"); String sanitized = new Csrf().permissive("<h1>title</h1><script src=\"other.js\"></script><h3>sub-title</h3><div>Some text</div><p>Some more text</p>");
assertEquals("<h1>title</h1><h3>sub-title</h3><div>Some text</div><p>Some more text</p>", sanitized); assertEquals("<h1>title</h1><h3>sub-title</h3><div>Some text</div><p>Some more text</p>", sanitized);
} }
@Test @Test
public void should_remove_internal_scripts() { public void should_remove_internal_scripts() {
String sanitized = new Csrf().stripScripts("<h1>title</h1><script>alert('hello')</script><h3>sub-title</h3><div>Some text</div><p>Some more text</p>"); String sanitized = new Csrf().permissive("<h1>title</h1><script>alert('hello')</script><h3>sub-title</h3><div>Some text</div><p>Some more text</p>");
assertEquals("<h1>title</h1><h3>sub-title</h3><div>Some text</div><p>Some more text</p>", sanitized); assertEquals("<h1>title</h1><h3>sub-title</h3><div>Some text</div><p>Some more text</p>", sanitized);
} }
@ -24,14 +24,14 @@ public class CsrfTest {
public void should_allow_images() { public void should_allow_images() {
String img = "<img src=\"http://f.cl.ly/items/2o2H0a193B2U3i0c3S0j/Untitled.png\" alt=\"The Magazine\" title=\"The Magazine\" height=\"100\" width=\"100\" />"; String img = "<img src=\"http://f.cl.ly/items/2o2H0a193B2U3i0c3S0j/Untitled.png\" alt=\"The Magazine\" title=\"The Magazine\" height=\"100\" width=\"100\" />";
assertEquals(img, new Csrf().stripScripts(img)); assertEquals(img, new Csrf().permissive(img));
} }
@Test @Test
public void should_allow_links() { public void should_allow_links() {
String link = "<a href=\"http://scriptogr.am/ovanrijswijk\" title=\"title\">Oskar van Rijswijk</a>"; String link = "<a href=\"http://scriptogr.am/ovanrijswijk\" title=\"title\">Oskar van Rijswijk</a>";
assertEquals(link, new Csrf().stripScripts(link)); assertEquals(link, new Csrf().permissive(link));
} }
@Test @Test
@ -39,20 +39,27 @@ public class CsrfTest {
String vimeoEmbed = "<p><iframe src=\"http://player.vimeo.com/video/51827660?title=0&amp;byline=0&amp;portrait=0&amp;color=08452f\" width=\"720\" height=\"527\" frameborder=\"0\" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> <p>An excerpt from a three screen triptych which is a part of a bigger installation.<br /> Sound, photography &amp; video by Einat Schlagmann.</p></p>"; String vimeoEmbed = "<p><iframe src=\"http://player.vimeo.com/video/51827660?title=0&amp;byline=0&amp;portrait=0&amp;color=08452f\" width=\"720\" height=\"527\" frameborder=\"0\" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> <p>An excerpt from a three screen triptych which is a part of a bigger installation.<br /> Sound, photography &amp; video by Einat Schlagmann.</p></p>";
String expected = "<p><iframe src=\"http://player.vimeo.com/video/51827660?title&#61;0&amp;byline&#61;0&amp;portrait&#61;0&amp;color&#61;08452f\" width=\"720\" height=\"527\" frameborder=\"0\" webkitallowfullscreen=\"webkitallowfullscreen\" mozallowfullscreen=\"mozallowfullscreen\" allowfullscreen=\"allowfullscreen\"></iframe> </p><p>An excerpt from a three screen triptych which is a part of a bigger installation.<br /> Sound, photography &amp; video by Einat Schlagmann.</p>"; String expected = "<p><iframe src=\"http://player.vimeo.com/video/51827660?title&#61;0&amp;byline&#61;0&amp;portrait&#61;0&amp;color&#61;08452f\" width=\"720\" height=\"527\" frameborder=\"0\" webkitallowfullscreen=\"webkitallowfullscreen\" mozallowfullscreen=\"mozallowfullscreen\" allowfullscreen=\"allowfullscreen\"></iframe> </p><p>An excerpt from a three screen triptych which is a part of a bigger installation.<br /> Sound, photography &amp; video by Einat Schlagmann.</p>";
assertEquals(expected, new Csrf().stripScripts(vimeoEmbed)); assertEquals(expected, new Csrf().permissive(vimeoEmbed));
} }
@Test @Test
public void should_allow_tables() { public void should_allow_tables() {
String table = "<table><thead><th>header</th></thead><tbody><tr><td>cell</td></tr></tbody></table>"; String table = "<table><thead><th>header</th></thead><tbody><tr><td>cell</td></tr></tbody></table>";
assertEquals(table, new Csrf().stripScripts(table)); assertEquals(table, new Csrf().permissive(table));
} }
@Test @Test
public void should_allow_emphasis() { public void should_allow_emphasis() {
String emphasis = "<em>emphas</em>ised"; String emphasis = "<em>emphas</em>ised";
assertEquals(emphasis, new Csrf().stripScripts(emphasis)); assertEquals(emphasis, new Csrf().permissive(emphasis));
}
@Test
public void restrictive_should_only_allow_links() {
String html = "<a href=\"https://link.tent.is\" class=\"my-class\" rel=\"nofollow\">link</a> <em>emphasis</em> <b>bold</b>";
assertEquals("<a href=\"https://link.tent.is\" class=\"my-class\" rel=\"nofollow\">link</a> emphasis bold", new Csrf().restrictive(html));
} }
} }

View file

@ -0,0 +1,30 @@
package com.moandjiezana.tent.essayist.text;
import static org.junit.Assert.assertEquals;
import com.moandjiezana.tent.essayist.security.Csrf;
import org.junit.Test;
public class TextTransformationTest {
private final TextTransformation textTransformation = new TextTransformation(new Csrf());
@Test
public void should_expand_markdown_and_all_entities_in_essay() {
String text = "[Link](http://www.example.com) by ^mention is #good!";
String expected = "<p><a href=\"http://www.example.com\">Link</a> by <a class=\"label label-inverse\" href=\"https://mention.tent.is\">mention</a> is <a href=\"https://skate.io/search?q&#61;%23good\" title=\"#good\" class=\"hashtag\">#good</a>!</p>";
assertEquals(expected, textTransformation.transformEssay(text));
}
@Test
public void should_expand_all_entities_in_comment() {
String comment = "Hey ^somerandombloke, have you seen https://github.com/tent/tent.io/wiki/Explaining-Tent ?";
String expected = "Hey <a class=\"label label-inverse\" href=\"https://somerandombloke.tent.is\" rel=\"nofollow\">somerandombloke</a>, have you seen <a href=\"https://github.com/tent/tent.io/wiki/Explaining-Tent\" rel=\"nofollow\">https://github.com/tent/tent.io/wiki/Explaining-Tent</a> ?";
assertEquals(expected, textTransformation.transformComment(comment));
}
}