Skip to content
Snippets Groups Projects
Verified Commit 7035d806 authored by Torsten Grote's avatar Torsten Grote
Browse files

Clean HTML from RSS feeds with Jsoup and show Link Warning

parent 2fbbb663
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/margin_large">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/link_warning_title"
android:textColor="@color/briar_primary"
android:textSize="@dimen/text_size_large"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_intro"
android:textColor="@color/briar_primary"
android:textSize="@dimen/text_size_medium"/>
<TextView
android:id="@+id/urlView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:textIsSelectable="true"
android:typeface="monospace"
tools:text="http://very.bad.site.com"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large"
android:text="@string/link_warning_text"
android:textColor="@color/briar_primary"
android:textSize="@dimen/text_size_medium"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/cancelButton"
style="@style/BriarButtonFlat.Positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="@string/cancel"/>
<Button
android:id="@+id/openButton"
style="@style/BriarButtonFlat.Negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="@string/link_warning_open_link"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
......@@ -308,6 +308,12 @@
<string name="feedback_settings_title">Feedback</string>
<string name="send_feedback">Send feedback</string>
<!-- Link Warning -->
<string name="link_warning_title">Link Warning</string>
<string name="link_warning_intro">You are about to open the following link with an external app.</string>
<string name="link_warning_text">This can be used to identify you. Think about whether you trust the person that sent you this link and consider opening it with Orfox.</string>
<string name="link_warning_open_link">Open Link</string>
<!-- Multiple Identities -->
<string name="anonymous">Anonymous</string>
<string name="new_identity_title">New Identity</string>
......
......@@ -30,6 +30,8 @@ import static org.briarproject.android.BriarActivity.GROUP_ID;
import static org.briarproject.android.blogs.BasePostPagerFragment.POST_ID;
import static org.briarproject.android.util.AndroidUtils.TEASER_LENGTH;
import static org.briarproject.android.util.AndroidUtils.getTeaser;
import static org.briarproject.android.util.AndroidUtils.getSpanned;
import static org.briarproject.android.util.AndroidUtils.makeLinksClickable;
import static org.briarproject.api.blogs.MessageType.POST;
@UiThread
......@@ -108,15 +110,17 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
}
// post body
CharSequence bodyText = item.getBody();
if (listener == null) {
body.setText(getSpanned(item.getBody()));
makeLinksClickable(body);
body.setTextIsSelectable(true);
} else {
body.setTextIsSelectable(false);
if (item.getBody().length() > TEASER_LENGTH)
bodyText = getTeaser(ctx, item.getBody());
body.setText(getTeaser(ctx, item.getBody()));
else
body.setText(item.getBody());
}
body.setText(bodyText);
// reblog button
reblogButton.setOnClickListener(new OnClickListener() {
......
......@@ -6,14 +6,24 @@ import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.URLSpan;
import android.view.View;
import android.widget.TextView;
import org.briarproject.R;
import org.briarproject.android.widget.LinkDialogFragment;
import org.briarproject.util.IoUtils;
import org.briarproject.util.StringUtils;
......@@ -142,4 +152,31 @@ public class AndroidUtils {
return builder;
}
public static Spanned getSpanned(String s) {
return Html.fromHtml(s);
}
public static void makeLinksClickable(TextView v) {
SpannableStringBuilder ssb = new SpannableStringBuilder(v.getText());
URLSpan[] spans = ssb.getSpans(0, ssb.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = ssb.getSpanStart(span);
int end = ssb.getSpanEnd(span);
final String url = span.getURL();
ssb.removeSpan(span);
ClickableSpan cSpan = new ClickableSpan() {
@Override
public void onClick(View v2) {
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
FragmentManager fm = ((AppCompatActivity) v2.getContext())
.getSupportFragmentManager();
f.show(fm, f.getUniqueTag());
}
};
ssb.setSpan(cSpan, start, end, 0);
}
v.setText(ssb);
v.setMovementMethod(LinkMovementMethod.getInstance());
}
}
package org.briarproject.android.widget;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import org.briarproject.R;
public class LinkDialogFragment extends DialogFragment {
private static final String TAG = LinkDialogFragment.class.getName();
private String url;
public static LinkDialogFragment newInstance(String url) {
LinkDialogFragment f = new LinkDialogFragment();
Bundle args = new Bundle();
args.putString("url", url);
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
url = getArguments().getString("url");
setStyle(STYLE_NO_TITLE, R.style.BriarDialogTheme);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_link_dialog, container,
false);
TextView urlView = (TextView) v.findViewById(R.id.urlView);
urlView.setText(url);
Button openButton = (Button) v.findViewById(R.id.openButton);
openButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
}
});
Button cancelButton = (Button) v.findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
getDialog().cancel();
}
});
return v;
}
public String getUniqueTag() {
return TAG;
}
}
......@@ -13,6 +13,7 @@ dependencies {
compile 'org.jdom:jdom2:2.0.6'
compile 'org.slf4j:slf4j-api:1.7.21'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'org.jsoup:jsoup:1.9.2'
}
dependencyVerification {
......@@ -25,6 +26,7 @@ dependencyVerification {
'com.squareup.okhttp3:okhttp:a47f4efa166551cd5acc04f1071d82dafbf05638c21f9ca13068bc6633e3bff6',
'com.rometools:rome-utils:2be18a1edc601c31fe49c2000bb5484dd75182309270c2a2561d71888d81587a',
'com.squareup.okio:okio:5cfea5afe6c6e441a4dbf6053a07a733b1249d1009382eb44ac2255ccedd0c15',
'org.jsoup:jsoup:9c1885f1b182256e06f1e30b8451caed0c0dee96299d6348f968d18b54d0a46a',
]
}
......
......@@ -66,6 +66,9 @@ import static org.briarproject.api.feed.FeedConstants.FETCH_DELAY_INITIAL;
import static org.briarproject.api.feed.FeedConstants.FETCH_INTERVAL;
import static org.briarproject.api.feed.FeedConstants.FETCH_UNIT;
import static org.briarproject.api.feed.FeedConstants.KEY_FEEDS;
import static org.briarproject.util.HtmlUtils.article;
import static org.briarproject.util.HtmlUtils.clean;
import static org.briarproject.util.HtmlUtils.stripAll;
class FeedManagerImpl implements FeedManager, Client, EventListener {
......@@ -337,13 +340,13 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
SyndFeed f = getSyndFeed(getFeedInputStream(feed.getUrl()));
title = StringUtils.isNullOrEmpty(f.getTitle()) ? null : f.getTitle();
if (title != null) title = stripHTML(title);
if (title != null) title = clean(title, stripAll);
description = StringUtils.isNullOrEmpty(f.getDescription()) ? null :
f.getDescription();
if (description != null) description = stripHTML(description);
if (description != null) description = clean(description, stripAll);
author =
StringUtils.isNullOrEmpty(f.getAuthor()) ? null : f.getAuthor();
if (author != null) author = stripHTML(author);
if (author != null) author = clean(author, stripAll);
if (f.getEntries().size() == 0)
throw new FeedException("Feed has no entries");
......@@ -418,23 +421,23 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
// build post body
StringBuilder b = new StringBuilder();
if (feed.getTitle() != null) {
// HTML in feed title was already stripped
b.append(feed.getTitle()).append("\n\n");
b.append("<h3>").append(feed.getTitle()).append("</h3>");
}
if (!StringUtils.isNullOrEmpty(entry.getTitle())) {
b.append(stripHTML(entry.getTitle())).append("\n\n");
b.append("<h1>").append(entry.getTitle()).append("</h1>");
}
for (SyndContent content : entry.getContents()) {
// extract content and do a very simple HTML tag stripping
if (content.getValue() != null)
b.append(stripHTML(content.getValue()));
b.append(content.getValue());
}
if (entry.getContents().size() == 0) {
if (entry.getDescription().getValue() != null)
b.append(stripHTML(entry.getDescription().getValue()));
if (entry.getDescription() != null &&
entry.getDescription().getValue() != null)
b.append(entry.getDescription().getValue());
}
b.append("<p>");
if (!StringUtils.isNullOrEmpty(entry.getAuthor())) {
b.append("\n\n-- ").append(stripHTML(entry.getAuthor()));
b.append("\n\n-- ").append(clean(entry.getAuthor(), stripAll));
}
if (entry.getPublishedDate() != null) {
b.append(" (").append(entry.getPublishedDate().toString())
......@@ -443,8 +446,11 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
b.append(" (").append(entry.getUpdatedDate().toString())
.append(")");
}
if (!StringUtils.isNullOrEmpty(entry.getLink())) {
b.append("\n\n").append(stripHTML(entry.getLink()));
b.append("</p>");
String link = entry.getLink();
if (!StringUtils.isNullOrEmpty(link)) {
b.append("<a href=\"").append(link).append("\">").append(link)
.append("</a>");
}
// get other information for post
......@@ -476,12 +482,8 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
}
}
private String stripHTML(String s) {
s = s.replaceAll("<script.*?>(?s).*?</script>", "");
return StringUtils.trim(s.replaceAll("<(?s).*?>", ""));
}
private String getPostBody(String text) {
text = clean(text, article);
if (text.length() <= MAX_BLOG_POST_BODY_LENGTH) return text;
else return text.substring(0, MAX_BLOG_POST_BODY_LENGTH);
}
......
package org.briarproject.util;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
public class HtmlUtils {
public static Whitelist stripAll = Whitelist.none();
public static Whitelist article =
Whitelist.basic().addTags("h1", "h2", "h3", "h4", "h5", "h6");
public static String clean(String s, Whitelist list) {
return Jsoup.clean(s, list);
}
}
package org.briarproject.util;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment