/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.extension.plugins.inner;

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.sql.Connection;

/**
 * 攻击 SQL 阻断解析器,防止全表更新与删除
 *
 * @author hubin
 * @since 3.4.0
 */
public class BlockAttackInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler handler = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = handler.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            if (InterceptorIgnoreHelper.willIgnoreBlockAttack(ms.getId())) return;
            BoundSql boundSql = handler.boundSql();
            parserMulti(boundSql.getSql(), null);
        }
    }

    @Override
    protected void processDelete(Delete delete, int index, String sql, Object obj) {
        this.checkWhere(delete.getWhere(), "Prohibition of full table deletion");
    }

    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        this.checkWhere(update.getWhere(), "Prohibition of table update operation");
    }

    protected void checkWhere(Expression where, String ex) {
        Assert.notNull(where, ex);
        if (where instanceof EqualsTo) {
            // example: 1=1
            EqualsTo equalsTo = (EqualsTo) where;
            Expression leftExpression = equalsTo.getLeftExpression();
            Expression rightExpression = equalsTo.getRightExpression();
            Assert.isFalse(leftExpression.toString().equals(rightExpression.toString()), ex);
        } else if (where instanceof NotEqualsTo) {
            // example: 1 != 2
            NotEqualsTo notEqualsTo = (NotEqualsTo) where;
            Expression leftExpression = notEqualsTo.getLeftExpression();
            Expression rightExpression = notEqualsTo.getRightExpression();
            Assert.isTrue(leftExpression.toString().equals(rightExpression.toString()), ex);
        }
    }
}

@@ -976,16 +976,161 @@
 ession;%0A
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;%0Aimport net.sf.jsqlparser.expression.operators.conditional.OrExpression;%0A
 import n
@@ -1354,24 +1354,69 @@
 ate.Update;%0A
+import org.apache.commons.lang3.StringUtils;%0A
 import org.a
@@ -2854,28 +2854,165 @@
 ert.
-notNull
+isFalse(this.fullMatch
 (where
+)
 , ex);%0A
+    %7D%0A%0A    private boolean fullMatch(Expression where) %7B%0A        if (where == null) %7B%0A            return true;%0A        %7D%0A
     
@@ -3142,229 +3142,115 @@
     
-Expression leftExpression = equalsTo.getLeftExpression();%0A            Expression rightExpression = equalsTo.getRightExpression();%0A            Assert.isFalse(leftExpression.toString().equals(rightExpression.toString()), ex
+return StringUtils.equals(equalsTo.getLeftExpression().toString(), equalsTo.getRightExpression().toString()
 );%0A 
@@ -3405,35 +3405,78 @@
     
-Expression leftExpression =
+return !StringUtils.equals(notEqualsTo.getLeftExpression().toString(),
  not
@@ -3479,35 +3479,36 @@
  notEqualsTo.get
-Lef
+Righ
 tExpression();%0A 
@@ -3508,62 +3508,225 @@
 on()
-;%0A            Expression rightExpression = notEqualsTo
+.toString());%0A        %7D else if (where instanceof OrExpression) %7B%0A%0A            OrExpression orExpression = (OrExpression) where;%0A            return fullMatch(orExpression.getLeftExpression()) %7C%7C fullMatch(orExpression
 .get
@@ -3742,16 +3742,17 @@
 ession()
+)
 ;%0A      
@@ -3757,102 +3757,265 @@
     
-    Assert.isTrue(leftExpression.toString().equals(rightExpression.toString()), ex);%0A        %7D
+%7D else if (where instanceof AndExpression) %7B%0A%0A            AndExpression andExpression = (AndExpression) where;%0A            return fullMatch(andExpression.getLeftExpression()) && fullMatch(andExpression.getRightExpression());%0A        %7D%0A%0A        return false;
 %0A   

fix #2930 BlockAttackInnerInterceptor 很容易被攻击SQL绕过的问题