package com.drops.poc;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.drops.entity.ControllersFactory;
import com.drops.ui.MainController;
import com.drops.utils.*;

import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import java.util.UUID;

/**
 * @ClassName: SpringBootInfoCheck
 * @Description: TODO
 * @Author: Summer
 * @Date: 2021/7/28 9:23
 * @Version: v1.0.0
 * @Description:
 **/
public class SpringBootInfoCheck {
    public String url;
    public String method;
    private MainController mainController;
    private static final String DefalutEncoding = "UTF-8";
    public static SpringBootInfo info = new SpringBootInfo();
    public boolean SpringbootVersionV1 = false;
    private SpringBootUtil SpringbootUtils = new SpringBootUtil();

    public boolean isSpringbootVersionV1() {
        return SpringbootVersionV1;
    }

    public void setSpringbootVersionV1(boolean springbootVersionV1) {
        SpringbootVersionV1 = springbootVersionV1;
    }

    public SpringBootInfoCheck(){
        this.mainController = (MainController) ControllersFactory.controllers.get(MainController.class.getSimpleName());
    }


    /**
     * @Description: 对目标首先进行特征检测
     * @param target
     *
     * @return:
     */
    public  boolean CheckPointInfo(String target){
//        mainController.logTextArea.appendText(Utils.log("target is -> " + target);
        String url = URLUtil.normalizeURL(target + "404");
//        mainController.logTextArea.appendText(Utils.log("url is  -> " + url);
        HttpResponse response = HTTPUtils.getRequest(url);
        int statscode = response.getStatus();
        String context = response.body();
        if (statscode == 404 || statscode == 403){
            return context.contains("Whitelabel Error Page") || context.contains("There was an unexpected error");

        }
        return false;

    }

    public boolean check404(String target){
//        mainController.logTextArea.appendText(Utils.log("target is -> " + target);
        String url = URLUtil.normalizeURL(target) + UUID.randomUUID();
//        mainController.logTextArea.appendText(Utils.log("url is  -> " + url);
        return HTTPUtils.getRequest(url).getStatus() == 200;

    }




    // Spring Boot 1.x版本端点在根URL下注册。
    public  boolean checkActuatorPointV1(String target){
        for (String point : info.pointListV1){
            if (this.SpringbootUtils.checkPoint(target, point)){
                this.setSpringbootVersionV1(true);
            }
        }
        return false;
    }
    // Spring Boot 2.x版本端点移动到/actuator/路径
    public  boolean checkActuatorPointV2(String target){
        for (String point : info.pointListV2){
            if (this.SpringbootUtils.checkPoint(target, point)){
                this.setSpringbootVersionV1(false);
            }
        }
        return false;
    }

    // Spring Boot env端点存在环境属性覆盖和XStream反序列化漏洞
     void checkEnvPointV1(String addr){
         String url = URLUtil.normalizeURL(addr) + "env";
         HttpResponse response = HTTPUtils.getRequest(url);
         PropertiesBean properties = this.EnvParser(this.scannerOutput(new Scanner(ResponseUtil.getBoby(response))));
         this.parseProperties(properties);
         SnakeYAMLRCEPOC yamlrcepoc = new SnakeYAMLRCEPOC();
         if (!yamlrcepoc.hasSnakeYAMLRCE(url)){
             EurekaXstreamRCEPOC xstreamRCEPOC = new EurekaXstreamRCEPOC();
             if (!xstreamRCEPOC.hasEurekaXstreamRCE(url)){
                 JolokiaLogbackRCEPOC logbackRCEPOC = new JolokiaLogbackRCEPOC();
                 JolokiaRealmJNDIRCEPOC realmJNDIRCEPOC = new JolokiaRealmJNDIRCEPOC();
                 logbackRCEPOC.hasJolokiaLogbackRCE(url);
                 boolean f  = realmJNDIRCEPOC.hasJolokiaRealmJNDIRCE(url);
                 if(!f){
                     H2DatabaseConsoleJNDIRCEPOC h2 = new H2DatabaseConsoleJNDIRCEPOC();
                     if (!h2.hasH2DatabaseConsoleJNDIRCE(url)){
                         SpringCloudGatewayRCEPOC gatewayRCEPOC = new SpringCloudGatewayRCEPOC();
                         if (!gatewayRCEPOC.hasSpringCloudGatewayRCEPOC(addr)){

                         }
                     }

                 }
             }
         }
    }

    // Spring Boot 2.x版本存在H2配置不当导致的RCE，目前非正则判断，测试阶段
     void checkEnvPointV2(String addr){
         final String url = addr+"actuator/env";
         HttpResponse response = HTTPUtils.getRequest(url);
         PropertiesBean properties = this.EnvParser(this.scannerOutput(new Scanner(ResponseUtil.getBoby(response))));
         this.parseProperties(properties);
         SnakeYAMLRCEPOC yamlrcepoc = new SnakeYAMLRCEPOC();
         if (!yamlrcepoc.hasSnakeYAMLRCE(url)){
             EurekaXstreamRCEPOC xstreamRCEPOC = new EurekaXstreamRCEPOC();
             if (!xstreamRCEPOC.hasEurekaXstreamRCE(url)){
                 JolokiaLogbackRCEPOC logbackRCEPOC = new JolokiaLogbackRCEPOC();
                 JolokiaRealmJNDIRCEPOC realmJNDIRCEPOC = new JolokiaRealmJNDIRCEPOC();
                 if(!logbackRCEPOC.hasJolokiaLogbackRCE(url) || realmJNDIRCEPOC.hasJolokiaRealmJNDIRCE(url)){
                     H2DatabaseConsoleJNDIRCEPOC h2 = new H2DatabaseConsoleJNDIRCEPOC();
                     if (!h2.hasH2DatabaseConsoleJNDIRCE(url)){
                         SpringCloudGatewayRCEPOC gatewayRCEPOC = new SpringCloudGatewayRCEPOC();
                         if (!gatewayRCEPOC.hasSpringCloudGatewayRCEPOC(addr)){

                         }
                     }

                 }
                 }
             }
         }





    public  PropertiesBean EnvParser(String result){
        PropertiesBean propertiesBean = new PropertiesBean();
        try {
            JSONObject jsonObject = JSON.parseObject(result);
            JSONArray propertySources = jsonObject.getJSONArray("propertySources");
            JSONObject propertySource;
            if (propertySources.size() > 0) {
                for (int i = 0; i < propertySources.size(); i++) {
                    propertySource = propertySources.getJSONObject(i);
                    String name = (String) propertySource.get("name");
                    if ("systemProperties".equals(name)) {
                        JSONObject properties = propertySource.getJSONObject("properties");
                        String jvmName = properties.getJSONObject("java.vm.name").getString("value");
                        String javaVersion = properties.getJSONObject("java.runtime.version").getString("value");
                        String userName = properties.getJSONObject("user.name").getString("value");
                        propertiesBean.setHaveInfo(true);
                        propertiesBean.setJvmName(jvmName);
                        propertiesBean.setJavaVersion(javaVersion);
                        propertiesBean.setUserName(userName);
                    } else if ("server.ports".equals(name)) {
                        propertiesBean.setHaveInfo(true);
                        JSONObject properties = propertySource.getJSONObject("properties");
                        String serverPort = properties.getJSONObject("local.server.port").getString("value");
                        propertiesBean.setServerPort(serverPort);
                    }

                }

            }
        }catch (Exception e){
            propertiesBean.setHaveInfo(false);
        }
        return propertiesBean;
    }




    public  String scannerOutput(Scanner scanner){
        StringBuilder builder = new StringBuilder();
        while (scanner.hasNext()){
            builder.append(scanner.nextLine()).append("\n");
        }
        return builder.toString();
    }


    void parseProperties(PropertiesBean properties){
        if (properties.getHaveInfo()){
//            this.mainController.logTextArea.appendText();
//            infoCheck.
            this.mainController.logTextArea.appendText(Utils.log("\tJVM信息:\t\t"+properties.getJvmName()));
            this.mainController.logTextArea.appendText(Utils.log("\t端口信息:\t\t"+properties.getServerPort()));
            this.mainController.logTextArea.appendText(Utils.log("\tJava版本:\t\t"+properties.getJavaVersion()));
            this.mainController.logTextArea.appendText(Utils.log("\t用户名:\t\t"+properties.getUserName()));
        }
    }







}
