package org.xdi.oxauth.model.util;
import org.apache.log4j.Logger;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Javier Rojas Blum
* @version October 10, 2016
*/
public class URLPatternList {
private static final Logger LOG = Logger.getLogger(URLPatternList.class);
private List<URLPattern> urlPatternList;
public URLPatternList() {
this.urlPatternList = new ArrayList<URLPattern>();
}
public URLPatternList(List<String> urlPatternList) {
this();
if (urlPatternList != null) {
for (String urlPattern : urlPatternList) {
addListEntry(urlPattern);
}
}
}
public boolean isUrlListed(String uri) {
if (urlPatternList == null) {
return true;
}
URI parsedUri = URI.create(uri);
for (URLPattern pattern : urlPatternList) {
if (pattern.matches(parsedUri)) {
return true;
}
}
return false;
}
public void addListEntry(String urlPattern) {
if (urlPatternList != null) {
try {
if (urlPattern.compareTo("*") == 0) {
LOG.debug("Unlimited access to network resources");
urlPatternList = null;
} else { // specific access
Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
Matcher m = parts.matcher(urlPattern);
if (m.matches()) {
String scheme = m.group(2);
String host = m.group(4);
// Special case for two urls which are allowed to have empty hosts
if (("file".equals(scheme) || "content".equals(scheme)) && host == null) host = "*";
String port = m.group(8);
String path = m.group(9);
if (scheme == null) {
urlPatternList.add(new URLPattern("http", host, port, path));
urlPatternList.add(new URLPattern("https", host, port, path));
} else {
urlPatternList.add(new URLPattern(scheme, host, port, path));
}
}
}
} catch (Exception e) {
LOG.debug("Failed to add origin " + urlPattern);
}
}
}
private static class URLPattern {
public Pattern scheme;
public Pattern host;
public Integer port;
public Pattern path;
public URLPattern(String scheme, String host, String port, String path) throws MalformedURLException {
try {
if (scheme == null || "*".equals(scheme)) {
this.scheme = null;
} else {
this.scheme = Pattern.compile(regexFromPattern(scheme, false), Pattern.CASE_INSENSITIVE);
}
if ("*".equals(host)) {
this.host = null;
} else if (host.startsWith("*.")) {
this.host = Pattern.compile("([a-z0-9.-]*\\.)?" + regexFromPattern(host.substring(2), false), Pattern.CASE_INSENSITIVE);
} else {
this.host = Pattern.compile(regexFromPattern(host, false), Pattern.CASE_INSENSITIVE);
}
if (port == null || "*".equals(port)) {
this.port = null;
} else {
this.port = Integer.parseInt(port, 10);
}
if (path == null || "/*".equals(path)) {
this.path = null;
} else {
this.path = Pattern.compile(regexFromPattern(path, true));
}
} catch (NumberFormatException e) {
throw new MalformedURLException("Port must be a number");
}
}
public boolean matches(URI uri) {
try {
return ((scheme == null || scheme.matcher(uri.getScheme()).matches()) &&
(host == null || host.matcher(uri.getHost()).matches()) &&
(port == null || port.equals(uri.getPort())) &&
(path == null || path.matcher(uri.getPath()).matches()));
} catch (Exception e) {
LOG.debug(e.toString());
return false;
}
}
private String regexFromPattern(String pattern, boolean allowWildcards) {
final String toReplace = "\\.[]{}()^$?+|";
StringBuilder regex = new StringBuilder();
for (int i = 0; i < pattern.length(); i++) {
char c = pattern.charAt(i);
if (c == '*' && allowWildcards) {
regex.append(".");
} else if (toReplace.indexOf(c) > -1) {
regex.append('\\');
}
regex.append(c);
}
return regex.toString();
}
}
}