package de.tu_dresden.diplom.richter_mirko_mat2628335;

import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.app.Velocity;

import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.io.*;

import sun.misc.BASE64Encoder;

/**
 * Class that was used to perform some testings with certs and keystores (Maybe interesting
 * for later usage of the project by other students). Some codesnippets with interest that have been found
 * on the internet were added too.
 */
public class Tester {

   private static final Logger logger = Logger.getLogger(Tester.class);

   public static void main(String[] args) {
      Configuration conf = new Configuration(Configuration.APPLICATION_TESTER);
      //certificateTesting(conf);
      //certificateTesting2(conf);
      dummy();
      try {
         //exportPrivKeyPEM(conf);
      } catch (Exception e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   public static void dummy() {
      try {
         Velocity.init();
         String toResolve = "${acpProjectModuleDirUsageCounter}/WEB-INF/client1_agreeDigest_config.wsdd";
         VelocityContext context = new VelocityContext();
         context.put("acpProjectModuleDirUsageCounter", new String("E:/home"));
         StringWriter sw = new StringWriter();
         Velocity.evaluate(context, sw, "testString", toResolve);
         System.out.println(sw);
      } catch (ParseErrorException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (MethodInvocationException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (ResourceNotFoundException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (IOException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (Exception e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }

   }

   /**
    * Reads PEM-File, iterates over all its certificates and prints Subject and isuer
    *
    * @param conf The configuration.
    */
   private static void certificateTesting2(Configuration conf) {
      try {
         InputStream inStream = new FileInputStream(conf.getCertHome() + File.separator + "prototyp_authenticating_webservice/pub1_ws1/naked/publisher_and_ws_cert.pem");
         BufferedInputStream bis = new BufferedInputStream(inStream);
         CertificateFactory cf = CertificateFactory.getInstance("X.509");
         while (bis.available() > 0) {
            X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
            System.out.println("Subject: " + cert.getSubjectDN());
            System.out.println("Issuer : " + cert.getIssuerDN());
         }
         bis.close();
         inStream.close();
      } catch (CertificateException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (IOException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   /**
    * Checks signature-chain of some test-certificates
    *
    * @param conf The configuration
    */
   private static void certificateTesting(Configuration conf) {
      try {
         InputStream inStream = new FileInputStream(conf.getCertHome() + File.separator + "prototyp_authenticating_webservice/pub1_ws1/naked/ws_cert.pem");
         CertificateFactory cf = CertificateFactory.getInstance("X.509");
         X509Certificate pub1Ws1Cert = (X509Certificate) cf.generateCertificate(inStream);
         inStream.close();
         //System.out.println(pub1Ws1Cert);
         inStream = new FileInputStream(conf.getCertHome() + File.separator + "prototyp_authenticating_webservice/pub1_ws1/naked/publisher_cert.pem");
         X509Certificate publisherCert = (X509Certificate) cf.generateCertificate(inStream);
         System.out.println(inStream.available());
         inStream.close();
         //System.out.println(publisherCert);
         pub1Ws1Cert.verify(publisherCert.getPublicKey());
         System.out.println("Certificate of pub1_ws1 signed with the key of publisher_1!");
         PublicKey pub1Ws1PublicKey = pub1Ws1Cert.getPublicKey();
         System.out.println(pub1Ws1PublicKey.getAlgorithm());
      } catch (CertificateException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (IOException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (NoSuchProviderException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (SignatureException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (InvalidKeyException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   /**
    * Loads some keystore (configure properly bevor using) and reads some private und public key.
    *
    * @param conf The configuration.
    */
   private static void keystoreTesting(Configuration conf) {
      try {
         KeyStore store = KeyStore.getInstance("JKS");
         File file = new File(conf.getCertHome() + File.separator + ".diplom");
         System.out.println("Keystore-File exist: " + file.isFile());
         FileInputStream stream = new FileInputStream(file);
         store.load(stream, new char[]{'!', 'd', 'i', 'p', 'l', 'o', 'm'});
         Certificate cert = store.getCertificate("key_01");
         System.out.println("Certificate exists: " + (cert != null));
         PublicKey publicKey = cert.getPublicKey();
         System.out.println("Public key exists: " + (publicKey != null) + "; of type: " + publicKey.getClass().getName());
         PrivateKey privateKey = (PrivateKey) store.getKey("key_01", new char[]{'!', 'd', 'i', 'p', 'l', 'o', 'm'});
         System.out.println("Private key exists: " + (privateKey != null) + "; of type: " + privateKey.getClass().getName());
         KeyPair keyPair = new KeyPair(publicKey, privateKey);
      } catch (KeyStoreException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (FileNotFoundException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (IOException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (CertificateException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (UnrecoverableKeyException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   /**
    * Writes the content of some private key to standard-out (Base64 encoded)
    *
    * @param conf The configuration
    * @throws Exception
    */
   public static void exportPrivKeyPEM(Configuration conf) throws Exception {

      KeyStore ks = KeyStore.getInstance("JCEKS");
      String fileName = conf.getCertHome() + File.separator + ".keystoreACP";

      char[] passPhrase = "acprototyp".toCharArray();
      BASE64Encoder myB64 = new BASE64Encoder();


      File certificateFile = new File(fileName);
      ks.load(new FileInputStream(certificateFile), passPhrase);

      KeyPair kp = getPrivateKey(ks, "Admin", "ACPAdmin".toCharArray());

      PrivateKey privKey = kp.getPrivate();


      String b64 = myB64.encode(privKey.getEncoded());

      System.out.println("-----BEGIN PRIVATE KEY-----");
      System.out.println(b64);
      System.out.println("-----END PRIVATE KEY-----");

   }

   /**
    * Loads public and private key from store.
    * Found at http://javaalmanac.com/egs/java.security/GetKeyFromKs.html
    *
    * @param keystore The KeyStore to use.
    * @param alias    The alias to obtain the keys for.
    * @param password The password to use for private-key-grabbing.
    * @return
    */

   public static KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) {
      try {
         // Get private key
         Key key = keystore.getKey(alias, password);
         if (key instanceof PrivateKey) {
            // Get certificate of public key
            Certificate cert = keystore.getCertificate(alias);

            // Get public key
            PublicKey publicKey = cert.getPublicKey();

            // Return a key pair
            return new KeyPair(publicKey, (PrivateKey) key);
         }
      } catch (UnrecoverableKeyException e) {
      } catch (NoSuchAlgorithmException e) {
      } catch (KeyStoreException e) {
      }
      return null;
   }

}
