package com.bcxin.ins.filter;

import com.bcxin.ins.util.GlobalResources;
import com.bcxin.ins.utils.html.EscapeUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AntiSqlInjectionFilter implements Filter{
  
	
    @Override  
    public void destroy() {  
          
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest args0, ServletResponse args1,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest)args0;
        HttpServletResponse res=(HttpServletResponse)args1;
        //得到当前请求路径
        String url = req.getServletPath().replace("/","");
        if(StringUtils.isNotEmpty(url)){
            if(url.contains("apithrcheckLogin")){//第三方登陆状态设置接口，设置允许跨域
                res.setHeader("Access-Control-Allow-Origin", "*");
            }/*else{
                // 设置允许多个域名请求
                String[] allowDomains = {"https://estand.test.pss360.cn","http://qiye.baibaodun.cn:7006","https://pasp.bcx.bcxin.com.cn/"};
                Set allowOrigins = new HashSet(Arrays.asList(allowDomains));
                String originHeads = req.getHeader("Origin");
                if(allowOrigins.contains(originHeads)){
                    res.setHeader("Access-Control-Allow-Origin", originHeads);
                }
            }*/
        }
        //获得所有请求参数名
        Enumeration params = req.getParameterNames();
        String sql = "";
        while (params.hasMoreElements()) {
            //得到参数名
            String name = params.nextElement().toString();
            //System.out.println("name===========================" + name + "--");
            //得到参数对应值
            String[] value = req.getParameterValues(name);
            for (int i = 0; i < value.length; i++) {
                sql = sql + value[i];
            }
        }
        //System.out.println("============================SQL"+sql);
        //有sql关键字，跳转到error.html
        if (sqlValidate(sql)) {
            String Origin = req.getHeader("Origin");
//            if(referer.contains("?")){
//                referer+="&message=警告！！您的请求内容中含有非法字符";
//            }else{
//                referer+="?message=警告！！您的请求内容中含有非法字符";
//            }
            String path = Origin + "/admin/error/10011";
            res.sendRedirect(path);
//            res.setCharacterEncoding("utf-8");
//            res.getWriter().print("警告！！您的请求内容中含有非法字符："+sql);
//            throw new AuthenticationException("警告！！您的请求内容中含有非法字符：");
        } else {
            chain.doFilter(args0,args1);
        }
    }

    //效验
    protected static boolean sqlValidate(String str) {
        str = str.toLowerCase();//统一转为小写
        boolean flag = html2Text(str);
        if(!flag){
            flag = sql2Text(str);
        }
        return flag;

    }

    /**
     * <b>
     *     过滤动态sql,过滤包含部分关键字的字符串片段
     *     ，如果该拦截还是会漏掉一些动态sql语句，可以直接去掉字符串中的所有%20（空格）黏在一起的字符串是肯定跑不了sql的
     * </b>
     * @param str 字符串
     * @author ZXF
     * @create 2018/06/11 0011 10:00
     * @version
     * @注意事项 </b>
     */
    public static boolean sql2Text(String str) {
        String str2 = str.replaceAll(" ", "");
        String[] arr = str2.split("@");
        String splStr = "";
        if(arr.length>3){
            splStr = "@"+arr[1].substring(0,1);
        }
        //注释的地方是因为碰到同类型的邮箱时不适用
        if(str2.contains("cast(")
                ||str2.contains("exec(@")
                ||str2.contains("%20as%20")
                ||str2.contains("declare%20")
                ||str2.contains("%20varchar(")
                ||str2.contains("set%20")
//                || StringUtils.isNotEmpty(splStr) ? str2.split(splStr).length>=3: false
                ){
            return true;
        }
        return false;
    }

    /**
     * <b> 过滤html标签 </b>
     * @author ZXF
     * @create 2018/06/08 0008 18:00
     * @version
     * @注意事项 </b>
     */
    public static boolean html2Text(String str) {
//        Pattern p;
//        Matcher m;
        try {

            /**
             * 1.定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script>
             * 2.定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
             * 3.定义HTML标签的正则表达式
             * 4.定义HTML标签的正则表达式
             */
            String value = EscapeUtil.clean(str).trim();
            if(StringUtils.isNotEmpty(str)&&!str.equals(value)){
                return true;
            }
            //String[] regEx_arr = {"<((?i)script)[^>]*?>[\\s\\S]*?<\\/((?i)script)>","<((?i)style)[^>]*?>[\\s\\S]*?<\\/((?i)style)>","<[^>]+>","<[^>]+"};
//            String[] regEx_arr = {"<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>","<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>","<[^>]+>","<[^>]+"};
//            for (String regEx : regEx_arr) {
//                p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
//                m = p.matcher(str);
//                if(m.matches()){
//                    return true;
//                }
//            }
        } catch (Exception e) {
            System.err.println("Html2Text: " + e.getMessage());
        }
        return false;
    }

    public static void main(String[] args) {
        String sql = "<script>alert(1)</script>";
        sql = sql.toLowerCase();
        html2Text(sql);
    }
}
