/* Copyright rememberjava.com. Licensed under GPL 3. See http://rememberjava.com/license */
package com.shinemo.mpush.alloc;

import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.lang.ProcessBuilder.Redirect;
import java.net.InetSocketAddress;
import java.security.KeyStore;

/**
 * A HTTPS server using a self-signed TLS 1.2 key and certificate generated by
 * the Java keytool command.
 * <p>
 */
@SuppressWarnings("restriction")
public class HttpServerCreator {

    private static final File KEYSTORE_FILE = new File(System.getProperty("java.io.tmpdir"), "mpush.jks");

    private static final String KEYSTORE_PASSWORD = "mpush_2017";

    private static final String KEY_PASSWORD = "mpush_2017";

    /**
     * Generates a new self-signed certificate in /tmp/test.jks, if it does not
     * already exist.
     */
    private static void generateCertificate() throws Exception {
        if (KEYSTORE_FILE.exists()) return;

        System.setProperty("javax.net.debug", "all");

        File keytool = new File(System.getProperty("java.home"), "bin/keytool");

        String[] genkeyCmd = new String[]{
                keytool.toString(),
                "-genkey",
                "-keyalg", "RSA",
                "-alias", "mpush.com",
                "-validity", "365",
                "-keysize", "2048",
                "-dname", "cn=mpush.com,ou=mpush,o=OHUN .Inc,c=CN",
                "-keystore", KEYSTORE_FILE.getAbsolutePath(),
                "-storepass", KEYSTORE_PASSWORD,
                "-keypass", KEY_PASSWORD};

        System.out.println(String.join(" ", genkeyCmd));

        ProcessBuilder processBuilder = new ProcessBuilder(genkeyCmd);
        processBuilder.redirectErrorStream(true);
        processBuilder.redirectOutput(Redirect.INHERIT);
        processBuilder.redirectError(Redirect.INHERIT);
        Process exec = processBuilder.start();
        exec.waitFor();

        System.out.println("Exit value: " + exec.exitValue());

    }

    private static HttpsServer createHttpsServer(int port) throws Exception {
        generateCertificate();
        HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress(port), 0);
        SSLContext sslContext = getSslContext();
        httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
        return httpsServer;
    }

    private static HttpServer createHttpServer(int port) throws Exception {
        HttpServer httpServer = HttpServer.create(new InetSocketAddress(port), 0);
        return httpServer;
    }

    private static SSLContext getSslContext() throws Exception {
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(new FileInputStream(KEYSTORE_FILE), KEYSTORE_PASSWORD.toCharArray());

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, KEY_PASSWORD.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(ks);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        return sslContext;
    }

    public static HttpServer createServer(int port, boolean https) {
        try {
            if (https) {
                return HttpServerCreator.createHttpsServer(port);
            } else {
                return HttpServerCreator.createHttpServer(port);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}