package cn.myapps.runtime.security;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringUtils;

import cn.myapps.common.util.StringUtil;
import cn.myapps.common.util.PropertyUtil;

//import com.blogspot.radialmind.html.HTMLParser;
//import com.blogspot.radialmind.xss.XSSFilter;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

	HttpServletRequest orgRequest = null;

	public XssHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
		orgRequest = request;
	}

	/**
	 * 覆盖getParameter方法，将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取<br/>
	 * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
	 */
	@Override
	public String getParameter(String name) {
		String value = super.getParameter(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}

		return value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.ServletRequestWrapper#getParameterNames()
	 */
	@Override
	public Enumeration<String> getParameterNames() {
		return super.getParameterNames();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.servlet.ServletRequestWrapper#getParameterValues(java.lang.String)
	 */
	@Override
	public String[] getParameterValues(String name) {

		String[] arrayOfString1 = super.getParameterValues(name);
		if (arrayOfString1 == null)
			return null;
		int i = arrayOfString1.length;
		String[] arrayOfString2 = new String[i];
		for (int j = 0; j < i; j++) {
			arrayOfString2[j] = xssEncode(arrayOfString1[j]);
		}
		return arrayOfString2;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.ServletRequestWrapper#getParameterMap()
	 */
	@Override
	public Map<String, String[]> getParameterMap() {
		Map<String, String[]> paramMap =  super.getParameterMap();
		//paramMap = (HashMap<String, String[]>) paramMap.clone();
		Map<String, String[]> warpParameterMap = new HashMap<String, String[]>();

		for (Iterator iterator = paramMap.entrySet().iterator(); iterator
				.hasNext();) {
			Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) iterator
					.next();
			String[] values = entry.getValue();
			for (int i = 0; i < values.length; i++) {
				if (values[i] instanceof String) {
					values[i] = xssEncode(values[i]);
				}
			}
			warpParameterMap.put(entry.getKey(), values);
			//entry.setValue(values);
		}
		return warpParameterMap;
	}

	/**
	 * 覆盖getHeader方法，将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值，则通过super.getHeaders(name)来获取<br/>
	 * getHeaderNames 也可能需要覆盖
	 */
	@Override
	public String getHeader(String name) {

		String value = super.getHeader(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}
		return value;
	}

	/**
	 * 将容易引起xss漏洞的字符串过滤掉
	 * 
	 * @param s
	 * @return
	 */
	/**
	private static String xssEncode(String s) {
		if (s == null || s.isEmpty()) {
			return s;
		}

		StringReader reader = new StringReader(s);
		StringWriter writer = new StringWriter();
		try {
			HTMLParser.process(reader, writer, new XSSFilter(), true);

			return writer.toString();
		} catch (NullPointerException e) {
			return s;
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return null;

	}
	**/
	
	public String escape(String s)  
    {  
		String[] ignoreEscapeURL = new String[] {};
		String _ignoreEscapeURL = PropertyUtil.get("SecurityFilter.firewall.interceptor.keyword.ignoreEscapeURL");
		if (!StringUtil.isBlank(_ignoreEscapeURL)) {
			ignoreEscapeURL = _ignoreEscapeURL.split("\\|");
		}
		String currentUri = this.orgRequest.getRequestURI();
		for(int index = 0;index < ignoreEscapeURL.length;index++) {
			String ignoreEscapeURLItem = ignoreEscapeURL[index];
			if(StringUtils.isBlank(ignoreEscapeURLItem)) {
				continue;
			}
			if(currentUri.trim().toLowerCase().contains(ignoreEscapeURLItem.trim().toLowerCase())) {
				return s;
			}
		}
        StringBuilder sb = new StringBuilder(s.length() + 16);  
        for (int i = 0; i < s.length(); i++)  
        {  
            char c = s.charAt(i);  
            switch (c)  
            {  
            case '>':  
                sb.append('＞');// 全角大于号  
                break;  
            case '<':  
                sb.append('＜');// 全角小于号  
                break;  
            case '\'':  
                sb.append('‘');// 全角单引号  
                break;  
            case '\"':  
                sb.append('“');// 全角双引号  
                break;  
            case '\\':  
                sb.append('＼');// 全角斜线  
                break;  
            case '%':  
                 sb.append('％'); // 全角冒号
                 break;
            case '(':
            	sb.append('（'); // 全角左括号
            	 break;
            case ')':
            	sb.append('）'); // 全角右边括号
           	     break;  	 
            default:  
                sb.append(c);  
                break;  
            }  
  
        }  
        return sb.toString();  
    }  
      
      
    /** 
     * 将容易引起xss漏洞的半角字符直接替换成全角字符 
     *  
     * @param s 
     * @return 
     */  
    public String xssEncode(String s)  
    {  
        if (s == null || s.isEmpty())  
        {  
            return s;  
        }  
          
        String result = stripXSS(s);  
        if (null != result)  
        {  
            result = escape(result);  
        }  
          
        return result;  
    }  
      
	private String stripXSS(String value)   
    {  
        if (value != null)   
        {
            // NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to  
            // avoid encoded attacks.  
            // value = ESAPI.encoder().canonicalize(value);  
            // Avoid null characters  
            value = value.replaceAll("", "");  
            // Avoid anything between script tags  
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid anything in a src='...' type of expression  
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Remove any lonesome </script> tag  
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Remove any lonesome <script ...> tag  
            scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid eval(...) expressions  
            scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid expression(...) expressions  
            scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid javascript:... expressions  
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid vbscript:... expressions  
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Avoid onload= expressions  
            scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
              
            scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
              
            scriptPattern = Pattern.compile("</iframe>", Pattern.CASE_INSENSITIVE);  
            value = scriptPattern.matcher(value).replaceAll("");  
            // Remove any lonesome <script ...> tag  
            scriptPattern = Pattern.compile("<iframe(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  
            value = scriptPattern.matcher(value).replaceAll("");  
            
        }  
        return value;  
    }

	/**
	 * 获取最原始的request
	 * 
	 * @return
	 */
	public HttpServletRequest getOrgRequest() {
		return orgRequest;
	}

	/**
	 * 获取最原始的request的静态方法
	 * 
	 * @return
	 */
	public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
		if (req instanceof XssHttpServletRequestWrapper) {
			return ((XssHttpServletRequestWrapper) req).getOrgRequest();
		}

		return req;
	}

}