package com.bonus.common.core.utils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 安全验证的工具类
 * 提供用于检测SQL注入、特殊字符、脚本注入等的工具方法
 * 作者: GeYazhong
 * 日期: 2021/11/23 10:54
 */
public class SafeUtil {

    /**
     * 安全SQL模式，用于检测SQL注入的正则表达式
     * 包含常见的SQL注入关键字和注释符号
     */
    public final static String SAFE_SQL_PATTERN = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"
            + "(\\b(select|update|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";

    /**
     * 安全脚本模式，用于检测脚本注入的正则表达式
     * 由于平台中setfilter中使用多个参数时用到&符号，因此未包含&符号
     */
    public final static String SAFE_SCRIPT_PATTERN = "(\\||;|\\$|'|\\'|0x0d|0x0a|\\%27|\\%3B)";

    /**
     * 检查特殊字符的正则表达式
     * 用于判断字符串是否为数字、字母、下划线或汉字
     */
    public static final String CHECK_SPECIAL = "^[\u4E00-\u9FA5A-Za-z_][\u4E00-\u9FA5A-Za-z0-9_]{0,}$";

    /**
     * 验证字符串是否包含SQL注入关键字
     *
     * @param mark 需要检查的字符串
     * @return 如果包含SQL注入关键字返回true，否则返回false
     */
    public static boolean checkSafeSql(String mark) {
        if (mark != null && !"".equals(mark)) {
            return match(SAFE_SQL_PATTERN, mark.toLowerCase().trim());
        }
        return false;
    }

    /**
     * 验证字符串是否包含特殊字符
     *
     * @param mark 需要检查的字符串
     * @return 如果包含特殊字符返回true，否则返回false
     */
    public static boolean checkSpecial(String mark) {
        if (mark != null && !"".equals(mark)) {
            return match(SAFE_SQL_PATTERN, mark.toLowerCase().trim());
        }
        return false;
    }

    /**
     * 验证字符串是否包含特殊脚本字符
     *
     * @param mark 需要检查的字符串
     * @return 如果包含特殊脚本字符返回true，否则返回false
     */
    public static boolean checkScript(String mark) {
        if (mark != null && !"".equals(mark)) {
            return match(SAFE_SCRIPT_PATTERN, mark.toLowerCase().trim());
        }
        return false;
    }

    /**
     * 执行正则表达式匹配
     *
     * @param pattern 正则表达式模式
     * @param str 需要验证的字符串
     * @return 如果匹配返回true，否则返回false
     */
    private static boolean match(String pattern, String str) {
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(str);
        return m.find();
    }

    /**
     * 检查字符串是否符合正则表达式
     *
     * @param regex 正则表达式
     * @param orginal 需要检查的字符串
     * @return 如果匹配返回true，否则返回false
     */
    private static boolean isMatch(String regex, String orginal) {
        if (StringUtils.isEmpty(orginal)) {
            return false;
        }
        Pattern pattern = Pattern.compile(regex);
        Matcher isNum = pattern.matcher(orginal);
        return isNum.matches();
    }

    /**
     * 检查字符串是否为正整数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是正整数返回true，否则返回false
     */
    public static boolean isPositiveInteger(String orginal) {
        return isMatch("^\\+{0,1}[1-9]\\d*", orginal);
    }

    /**
     * 检查字符串是否为负整数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是负整数返回true，否则返回false
     */
    public static boolean isNegativeInteger(String orginal) {
        return isMatch("^-[1-9]\\d*", orginal);
    }

    /**
     * 检查字符串是否为整数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是整数返回true，否则返回false
     */
    public static boolean isWholeNumber(String orginal) {
        return isMatch("[+-]{0,1}0", orginal) || isPositiveInteger(orginal) || isNegativeInteger(orginal);
    }

    /**
     * 检查字符串是否为正小数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是正小数返回true，否则返回false
     */
    public static boolean isPositiveDecimal(String orginal) {
        return isMatch("\\+{0,1}[0]\\.[1-9]*|\\+{0,1}[1-9]\\d*\\.\\d*", orginal);
    }

    /**
     * 检查字符串是否为负小数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是负小数返回true，否则返回false
     */
    public static boolean isNegativeDecimal(String orginal) {
        return isMatch("^-[0]\\.[1-9]*|^-[1-9]\\d*\\.\\d*", orginal);
    }

    /**
     * 检查字符串是否为小数
     *
     * @param orginal 需要检查的字符串
     * @return 如果是小数返回true，否则返回false
     */
    public static boolean isDecimal(String orginal) {
        return isMatch("[-+]{0,1}\\d+\\.\\d*|[-+]{0,1}\\d*\\.\\d+", orginal);
    }

    /**
     * 检查字符串是否为实数（整数或小数）
     *
     * @param orginal 需要检查的字符串
     * @return 如果是实数返回true，否则返回false
     */
    public static boolean isRealNumber(String orginal) {
        return isWholeNumber(orginal) || isDecimal(orginal);
    }
}
