package com.yidianling.ydlcommon.custom.http;

import com.yidianling.ydlcommon.core.base.BaseApplication;
import com.yidianling.ydlcommon.BuildConfig;
import com.yidianling.ydlcommon.R;
import com.yidianling.ydlcommon.custom.remind.ToastHelper;

import javax.net.ssl.*;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

/**
 * Created by haorui on 2019/7/9.
 * Des:SSL证书工具类
 */
public class YDLSSLFactory {
    private static final String KEY_STORE_TYPE_BKS = "BKS";//证书类型
    private static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型

    private static final String KEY_STORE_PASSWORD = "123456";//证书密码（客户端证书密码）
    private static final String KEY_STORE_TRUST_PASSWORD = "123456";//授信证书密码（服务端证书密码）

    /**
     * 单向证书认证
     *
     * @returndailyContent
     */
    public static SSLSocketFactory getSocketFactory() {

        if (BuildConfig.DEBUG){
            return getTrustAllSocketFactory();
        }

        checkNetProxy();

        try {
            InputStream inputStream = BaseApplication.Companion.getApp().getResources().openRawResource(R.raw.ydl_trust);

            //keystore添加证书内容和密码
            KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
            keyStore.load(inputStream, KEY_STORE_PASSWORD.toCharArray());

            //key管理器工厂
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, KEY_STORE_PASSWORD.toCharArray());

            //证书工厂类，生成证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            //生成证书，添加别名
            keyStore.setCertificateEntry("certificate", certificateFactory.generateCertificate(inputStream));
            //信任管理器工厂
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //构建一个ssl上下文，加入ca证书格式，与后台保持一致
            SSLContext sslContext = SSLContext.getInstance("TLS");

            //参数，添加受信任证书和生成随机数
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

            //获得scoket工厂
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 双向证书认证
     * 目前服务器暂不支持双向认证
     * 使用时需要补充客户端证书
     *
     * @return
     */
    public static SSLSocketFactory getTwoWaySocketFactory() {

        if (BuildConfig.DEBUG){
            return getTrustAllSocketFactory();
        }

        checkNetProxy();

        try {
            //将ca证书导入输入流
            InputStream trust_input = BaseApplication.Companion.getApp().getResources().openRawResource(R.raw.ydl_trust);//服务器授信证书
            InputStream client_input = BaseApplication.Companion.getApp().getResources().openRawResource(R.raw.ydl_trust);//客户端证书

            //keystore添加证书内容和密码
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(trust_input, KEY_STORE_TRUST_PASSWORD.toCharArray());

            //证书工厂类，生成证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

            //生成证书，添加别名
            keyStore.setCertificateEntry("certificate", certificateFactory.generateCertificate(trust_input));

            //信任管理器工厂
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //双向验证，配置服务器验证客户端的证书
            KeyStore keyStore1 = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore1.load(client_input, KEY_STORE_PASSWORD.toCharArray());

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore1, KEY_STORE_PASSWORD.toCharArray());

            //构建一个ssl上下文，加入ca证书格式，与后台保持一致
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //参数，添加受信任证书和生成随机数
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

            //获得scoket工厂
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 信任所有的证书
     */
    private static SSLSocketFactory getTrustAllSocketFactory() {
        X509TrustManager xtm = getUnSafeTrustManager();

        SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("SSL");

            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (KeyManagementException e) {
            e.printStackTrace();
            return null;
        }
        return sslContext.getSocketFactory();
    }

    private static void checkNetProxy() {
        //代理服务检测
        if(System.getProperty("http.proxyHost") != null || System.getProperty("http.proxyPort") != null) {
            //正常情况下这两个返回值是null，如果发现不为空那么就表示当前设备被挂代理了，那么就有可能被抓包的风险了
            ToastHelper.Companion.show("当前设备正在使用代理服务，请注意应用安全");
        }
    }


    public static SafeTrustManager getSafeTrustManager(){
        return new SafeTrustManager();
    }

    public static UnSafeTrustManager getUnSafeTrustManager(){
        return new UnSafeTrustManager();
    }

    public static class UnSafeTrustManager implements X509TrustManager{
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException{}

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)throws CertificateException{}

        @Override
        public X509Certificate[] getAcceptedIssuers(){
            return new X509Certificate[]{};
        }
    }


    public static class SafeTrustManager implements X509TrustManager{

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException{}

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException{
            for (X509Certificate cert : chain) {
                cert.checkValidity();
                try {
                    cert.verify(cert.getPublicKey());
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (InvalidKeyException e) {
                    e.printStackTrace();
                } catch (NoSuchProviderException e) {
                    e.printStackTrace();
                } catch (SignatureException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers(){
            return new X509Certificate[0];
        }
    }

}
