/*
Copyright 2012-2013, Polyvi Inc. (http://polyvi.github.io/openxface)
This program is distributed under the terms of the GNU General Public License.
This file is part of xFace.
xFace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
xFace is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with xFace. If not, see <http://www.gnu.org/licenses/>.
*/
package com.polyvi.xface.app;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.polyvi.xface.util.XLog;
import com.polyvi.xface.util.XStringUtils;
public class XWhiteList {
private static final String CLASS_NAME = XWhiteList.class.getSimpleName();
/**用来白名单匹配的正则表达式*/
private static final String HTTP_SCHEME = "http";
private static final String HTTPS_SCHEME = "https?://";
private static final String HTTPS_SCHEME_START = "^https?://";
private static final String HTTP_SUBDOMAINS = "^https?://(.*\\\\.)?";//匹配子域名
/**应用访问白名单匹配数组 **/
private ArrayList<Pattern> mWhiteList = new ArrayList<Pattern>();
/**应用访问白名单的历史缓存,用于提高检查速度*/
private HashMap<String, Boolean> mWhiteListCache = new HashMap<String, Boolean>();
/**标示访问url是否无限制*/
private boolean mAccessNoLimit = true;
/**
* 添加允许访问的URL (白名单)
*
* @param origin 允许访问的URL正则表达式
* @param subdomains true:允许访问origin下所有子域名
*/
public void addWhiteListEntry(String origin, String subdomains) {
if(XStringUtils.isEmptyString(origin)){
XLog.w(CLASS_NAME, "origin attribute is absent in access");
return;
}
mAccessNoLimit = false;
mWhiteList.add(Pattern.compile(getRexPattern(origin,
(subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0))));
}
/**
* 检查url是否在白名单中
*
* @param url : 要检查的url
* @return true:在白名单中,false:不在白名单中
*/
public boolean isUrlWhiteListed(String url) {
/** 如果对访问无限制,则直接返回true */
if(mAccessNoLimit) {
return true;
}
/** 首先在白名单缓存中检查是否存在url,如果有就直接返回true */
if (mWhiteListCache.get(url) != null) {
return true;
}
/** 检查白名单 */
Iterator<Pattern> pit = mWhiteList.iterator();
while (pit.hasNext()) {
Pattern p = pit.next();
Matcher m = p.matcher(url);
/** 如果找到就在白名单缓存中放入url,这有助于加快查找速度 */
if (m.find()) {
mWhiteListCache.put(url, true);
return true;
}
}
return false;
}
/**
* 根据传入的origin和subdomains获取要编译的正则表达式
* @param origin:域名
* @param subdomains:origin的子域名是否允许被访问
* @return 要编译的正则表达式
*/
private String getRexPattern(String origin, boolean subdomains) {
/**如果origin为"*",则表示对访问的URL没有限制*/
if (origin.compareTo("*") == 0) {
XLog.d(CLASS_NAME, "Unlimited access to network resources");
return ".*";
} else {
/**检查是否子域名也允许访问*/
if (subdomains) {
XLog.d(CLASS_NAME, "Origin to allow with subdomains: %s", origin);
/**如果URL协议开头没有加上http,则自动加上*/
return origin.startsWith(HTTP_SCHEME) ?
origin.replaceFirst(HTTPS_SCHEME, HTTP_SUBDOMAINS) :
HTTP_SUBDOMAINS + origin;
} else {
XLog.d(CLASS_NAME, "Origin to allow: %s", origin);
/**如果URL协议开头没有加上http,则自动加上*/
return origin.startsWith(HTTP_SCHEME) ?
origin.replaceFirst(HTTPS_SCHEME, HTTPS_SCHEME_START) :
HTTPS_SCHEME_START + origin;
}
}
}
}