package helpers;
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import models.openfire.User;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;
import play.Logger;
import play.libs.F.Promise;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
import com.typesafe.config.ConfigFactory;
public class ContentHelper {
private final static String HTTP_YOUTU_BE = "http://youtu.be";
private final static String HTTPS_YOUTU_BE = "https://youtu.be";
private final static String HTTP_WWW_YOUTUBE_COM = "http://www.youtube.com";
private final static String HTTPS_WWW_YOUTUBE_COM = "https://www.youtube.com";
private final static String HTTPS_WWW_YOUTUBE_COM_EMBED = "https://www.youtube.com/embed";
private String content;
private final static Pattern URL_PATTERN = Pattern.compile("\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
private final static int MAX_GET_TIMEOUT = 2500;
private final static String USER_URL_TEMPLATE = ConfigFactory.load().getString("user.url.template");
private final static String[] INVALID_USERNAME_PARTS = {":", ","};
public ContentHelper(String content) {
this.content = content;
}
public static String prepare(String content) {
if (content == null) {
return content;
}
ContentHelper ch = new ContentHelper(content.trim());
return ch.renderHtml().detectUsers().sanitize().detectLinks().normalize().toString();
}
public ContentHelper normalize() {
content = content.replace("\n", "
\n");
return this;
}
public ContentHelper renderHtml() {
content = content.replace("<", "<").replace(">", ">");
return this;
}
public ContentHelper sanitize() {
PolicyFactory policy = new HtmlPolicyBuilder()
.allowUrlProtocols("http")
.allowUrlProtocols("https")
.allowElements("a")
.allowElements("img")
.allowElements("br")
.allowAttributes("href")
.onElements("a")
.allowAttributes("target")
.onElements("a")
.allowAttributes("src")
.onElements("img")
.requireRelNofollowOnLinks()
.toFactory();
content = policy.sanitize(content);
return this;
}
public ContentHelper detectLinks() {
String urlStr, oldLine;
StringBuilder contentBuilder = new StringBuilder();
for (String line : content.split("\n")) {
oldLine = line.trim();
Matcher m = URL_PATTERN.matcher(line);
while (m.find()) {
urlStr = m.group();
Logger.debug("found link |" + urlStr + "|");
line = line.replace(urlStr, embedLink(getUrl(urlStr)));
if(urlStr.startsWith(HTTP_WWW_YOUTUBE_COM) || urlStr.startsWith(HTTPS_WWW_YOUTUBE_COM)) {
Logger.debug("YOUTUBE_COM: "+line);
line += "
"+embedYT(getUrl(urlStr));
}
if(urlStr.startsWith(HTTP_YOUTU_BE) || urlStr.startsWith(HTTPS_YOUTU_BE)) {
Logger.debug("YOUTU_BE: "+line);
line += "
"+embedYT(convertShortYTUrl(urlStr));
}
if(getUrl(oldLine).equals(urlStr)) {
line += "
"+embedImage(getUrl(urlStr));
}
}
contentBuilder.append(line.trim());
contentBuilder.append("\n");
}
content = contentBuilder.toString();
return this;
}
public ContentHelper detectUsers() {
StringBuilder contentBuilder = new StringBuilder();
for (String line : content.split("\n")) {
contentBuilder = detectUser(contentBuilder, line);
}
content = contentBuilder.toString();
return this;
}
private String getUrl(String url) {
try {
return URLDecoder.decode(url, "UTF-8");
} catch(java.lang.IllegalArgumentException ex) {
Logger.warn(ex.getLocalizedMessage(), ex);
} catch(java.io.UnsupportedEncodingException ex) {
Logger.warn(ex.getLocalizedMessage(), ex);
}
String[] find = {"=", "%3A", "%2F"};
String[] replace = {"=", ":", "/"};
for(int i=0; i < find.length; i++) {
url.replace(find[i], replace[i]);
}
return url;
}
private StringBuilder detectUser(StringBuilder contentBuilder, String line){
int start, end;
String user, cleanuser;
if (line.contains(" @") || line.startsWith("@")) {
start = line.indexOf(" @") + 1;
if (start < 0 || line.startsWith("@"))
start = 0;
end = Math.min(line.substring(start).indexOf(" ")+start, line.length());
if (end < start)
end = line.length();
if(end > start){
user = line.substring(start + 1, end);
cleanuser = user.trim().toLowerCase();
for(String part : INVALID_USERNAME_PARTS){
cleanuser = cleanuser.replace(part, "");
}
Logger.debug("found user |" + user + "| " + start + "-" + end);
if(User.exists(cleanuser)) {
contentBuilder.append(line.substring(0, start)).append("@"+user+" ");
} else {
contentBuilder.append(line.trim());
}
}else {
Logger.warn("false user in: "+line.trim());
contentBuilder.append(line.trim());
}
return detectUser(contentBuilder, line.substring(Math.min(end+1, line.length())));
} else {
contentBuilder.append(line.trim());
}
return contentBuilder;
}
public String toString() {
return this.content;
}
private String embedLink(String urlStr) {
return "" + urlStr + "";
}
private String embedYT(String urlStr) {
Map paras = getParametersFromUrl(urlStr);
if(paras.containsKey("v")) {
return "";
}
return "";
}
private String embedImage(String urlStr) {
try {
//urlStr = URLEncoder.encode(urlStr, "UTF-8");
Promise response = WS.url(urlStr).get();
try {
if (response.get(MAX_GET_TIMEOUT).getHeader("Content-Type").startsWith("image")) {
return "
";
}
} catch (Exception ex) {
Logger.warn(ex.getLocalizedMessage());
}
} catch (Exception ex) {
Logger.warn(ex.getLocalizedMessage());
}
return "";
}
private static String buildEmbeddedYTUrl(Map paras){
StringBuilder sb = new StringBuilder(HTTPS_WWW_YOUTUBE_COM_EMBED);
if(paras.containsKey("v")){
sb.append("/"+paras.get("v"));
}
if(paras.containsKey("t")){
sb.append("?start="+paras.get("t").replace("s", ""));
}
return sb.toString();
}
private static String convertShortYTUrl(String shortYTUrl) {
Map map = new HashMap();
shortYTUrl = shortYTUrl.replace(HTTPS_YOUTU_BE, "").replace(HTTP_YOUTU_BE, "").replace("=", "=").trim();
String params[] = shortYTUrl.split("[/,?]");
for (String param : params) {
try {
if(param.split("=").length == 2) {
map.put(param.split("=")[0], param.split("=")[1]);
} else if(!param.isEmpty()) {
map.put("v", param);
}
} catch (Exception e) {
Logger.warn("No value for parameter "+param+" in shortYTUrl "+shortYTUrl);
}
}
return HTTPS_WWW_YOUTUBE_COM+"/watch?v="+map.get("v")+"&t="+map.get("t");
}
private static Map getParametersFromUrl(String url) {
Map map = new HashMap();
if (url != null) {
String[] params = url.trim().split("[&,?]");
for (String param : params) {
try {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
} catch (Exception e) {
Logger.warn("No value for parameter "+param+" in "+url);
}
}
}
return map;
}
}