package cn.com.victorysoft.business.filter;

import cn.com.victorysoft.business.utils.FilterUtils;
import cn.com.victorysoft.business.utils.SpringUtils;
import net.sf.json.JSONObject;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;

import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.regex.Pattern;

/**
 * 参数过滤器
 * @author stareast
 */
public class ParameterFilter implements Filter {

    private MultipartResolver multipartResolver = null;

    private Pattern scriptPattern;
    private Pattern sqlPattern;
    private Pattern letterPattern;
    private String notProtect = "";
    private String totalLetter = "";

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain filtreChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String contentType = request.getContentType() == null ? "" : request
                .getContentType();
        // %uff07为单引号的编码
        String[] blankStr = {"alert", "script", " and ", " or ", "delete ", "drop ", "%uff07"};

        if (!contentType.startsWith("multipart/form-data")
                && !FilterUtils.isContainUrl(notProtect, FilterUtils.getFullUrlFromRequest(req))) {
            Enumeration enu = req.getParameterNames();

            boolean isSecurity = true;
            while (enu.hasMoreElements()) {
                String para_name = (String) enu.nextElement();
                String[] para_value = null;
                para_value = (String[]) req.getParameterValues(para_name);
                for (int i = 0; i < para_value.length; i++) {
                    String _para_value = para_value[i].toLowerCase();

                    for (int j = 0; j < blankStr.length; j++) {
                        if (_para_value.indexOf(blankStr[j]) >= 0) {
                            isSecurity = false;
                            break;
                        }
                    }
                    if (scriptPattern.matcher(_para_value).matches()
                            || sqlPattern.matcher(_para_value).matches()) {

                        isSecurity = false;
                        break;
                    }
                }
                if (!isSecurity)
                    break;
            }
            if (!isSecurity) {
                PrintWriter out = null;
                response.setCharacterEncoding("UTF-8");

                response.setContentType("application/json; charset=utf-8");
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("success", false);
                jsonObject.put("msg", "输入有误,请不要包含任何敏感字符!");
                jsonObject.put("status", 400);
                jsonObject.put("data", null);
                out = response.getWriter();
                out.append(jsonObject.toString());
                return;
            }

        } else if (contentType.startsWith("multipart/form-data")) {
            MultipartHttpServletRequest multipartRequest = multipartResolver.resolveMultipart((HttpServletRequest) request);

            Enumeration enu = multipartRequest.getParameterNames();

            boolean isSecurity = true;
            while (enu.hasMoreElements()) {
                String para_name = (String) enu.nextElement();
                String[] para_value = null;
                para_value = (String[]) multipartRequest.getParameterValues(para_name);
                for (int i = 0; i < para_value.length; i++) {
                    String _para_value = para_value[i].toLowerCase();

                    for (int j = 0; j < blankStr.length; j++) {
                        if (_para_value.indexOf(blankStr[j]) >= 0) {
                            isSecurity = false;
                            break;
                        }
                    }
                    if (scriptPattern.matcher(_para_value).matches()
                            || sqlPattern.matcher(_para_value).matches()) {
                        isSecurity = false;
                        break;
                    }
                }
                if (!isSecurity)
                    break;
            }
            if (!isSecurity) {
                PrintWriter out = null;
                response.setCharacterEncoding("UTF-8");

                response.setContentType("application/json; charset=utf-8");
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("success", false);
                jsonObject.put("msg", "输入有误,请不要包含任何敏感字符!");
                jsonObject.put("status", 400);
                jsonObject.put("data", null);
                out = response.getWriter();
                out.append(jsonObject.toString());

                return;
            }
//            request = multipartRequest;
        }

        filtreChain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        multipartResolver = ((MultipartResolver) SpringUtils.getBean("multipartResolver", MultipartResolver.class));
        letterPattern = Pattern.compile("[a-z]*");
        String scriptPara = filterConfig.getInitParameter("scriptRegx").toLowerCase();
        String sqlPara = filterConfig.getInitParameter("sqlRegx").toLowerCase();
        notProtect = filterConfig.getInitParameter("notProtect");
        scriptPattern = Pattern.compile(resultStr(scriptPara));
        sqlPattern = Pattern.compile(resultStr(sqlPara));
        totalLetter = scriptPara + "|" + sqlPara;
        int index = totalLetter.indexOf("'");
        if (index > 0) {
            totalLetter = totalLetter.substring(0, index) + "\\'" + totalLetter.substring(index + 1);
        }
    }

    public String resultStr(String oldStr) {
        String newStr = "";
        if (oldStr != null && !oldStr.equals("")) {
            String[] temp = oldStr.split("\\|");
            if (temp.length > 0) {
                for (int i = 0; i < temp.length; i++) {
                    String tempStr = "";
                    boolean isLetter = false;
                    for (int j = 0; j < temp[i].length(); j++) {
                        String str = temp[i].substring(j, j + 1);
                        if (letterPattern.matcher(str).matches()) {
                            tempStr = tempStr + "((\\%" + parseAscii(str.toUpperCase()) + ")|" + "(\\%" + parseAscii(str) + ")|(" + str + "))";
                            isLetter = true;
                        } else {
                            if (str.equals("(") || str.equals(")"))
                                str = "\\" + str;
                            tempStr = tempStr + "((\\%" + parseAscii(str) + ")|(" + str + "))";
                            isLetter = false;
                        }
                    }
                    if (isLetter)
                        if (newStr.equals("")) {
                            newStr = newStr + ".*(\\s+)(" + tempStr + ")(\\s+).*";
                        } else {
                            newStr = newStr + "|.*(\\s+)(" + tempStr + ")(\\s+).*";
                        }
                    else if (newStr.equals("")) {
                        newStr = newStr + ".*(" + tempStr + ").*";
                    } else {
                        newStr = newStr + "|.*(" + tempStr + ").*";
                    }
                }
            }
        }
        return newStr;
    }

    private String toHexUtil(int n) {
        String rt = "";
        switch (n) {
            case 10:
                rt += "A";
                break;
            case 11:
                rt += "B";
                break;
            case 12:
                rt += "C";
                break;
            case 13:
                rt += "D";
                break;
            case 14:
                rt += "E";
                break;
            case 15:
                rt += "F";
                break;
            default:
                rt += n;
        }
        return rt;
    }

    public String toHex(int n) {
        StringBuffer sb = new StringBuffer();
        if (n / 16 == 0) {
            return toHexUtil(n);
        } else {
            String t = toHex(n / 16);
            int nn = n % 16;
            sb.append(t).append(toHexUtil(nn));
        }
        return sb.toString();
    }

    public String parseAscii(String str) {
        StringBuffer sb = new StringBuffer();
        byte[] bs = str.getBytes();
        for (int i = 0; i < bs.length; i++)
            sb.append(toHex(bs[i]));
        return sb.toString();
    }
}
