package com.airlock.iam.security.certificate;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.Base64;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;

public final class CertificateIO {
   private static final ELogger LOG = ELoggerFactory.getLogger(CertificateIO.class);

   public static String convertToPem(X509Certificate certificate) {
      StringWriter result = new StringWriter();

      try {
         JcaPEMWriter pemWriter = new JcaPEMWriter(result);

         try {
            pemWriter.writeObject(certificate);
            pemWriter.flush();
         } catch (Throwable var6) {
            try {
               pemWriter.close();
            } catch (Throwable var5) {
               var6.addSuppressed(var5);
            }

            throw var6;
         }

         pemWriter.close();
      } catch (IOException e) {
         throw new IllegalStateException(e);
      }

      return result.toString();
   }

   public static Collection<Certificate> load(Path certificate) throws CertificateException, IOException {
      try (InputStream in = Files.newInputStream(certificate)) {
         return load(in);
      }
   }

   public static Collection<Certificate> load(InputStream in) throws CertificateException {
      return CertificateFactory.getInstance("X.509").generateCertificates(in).stream().map(Certificate.class::cast).collect(Collectors.toList());
   }

   public static Optional<X509Certificate> loadFirstX509(InputStream in) throws CertificateException {
      return load(in).stream().findFirst().filter(X509Certificate.class::isInstance).map(X509Certificate.class::cast);
   }

   private CertificateIO() {
      throw new AssertionError();
   }

   public static String toPEM(X509Certificate certificate) {
      try (ByteArrayOutputStream pem = new ByteArrayOutputStream()) {
         JcaPEMWriter pemWriter = new JcaPEMWriter(new OutputStreamWriter(pem, StandardCharsets.UTF_8));

         String var3;
         try {
            pemWriter.writeObject(certificate);
            pemWriter.flush();
            var3 = new String(pem.toByteArray(), StandardCharsets.UTF_8);
         } catch (Throwable var7) {
            try {
               pemWriter.close();
            } catch (Throwable var6) {
               var7.addSuppressed(var6);
            }

            throw var7;
         }

         pemWriter.close();
         return var3;
      } catch (IOException e) {
         throw new IllegalStateException(e);
      }
   }

   public static Optional<String> asPemEncodedString(X509Certificate certificate) {
      try {
         Charset charset = Charset.defaultCharset();
         return Optional.of(asPem(certificate, charset));
      } catch (CertificateEncodingException e) {
         LOG.info("Could not get PEM encoded representation for certificate: " + e.getMessage());
         return Optional.empty();
      }
   }

   private static String asPem(X509Certificate certificate, Charset charset) throws CertificateEncodingException {
      return "-----BEGIN CERTIFICATE-----\r\n"
         + new String(Base64.getMimeEncoder(64, "\r\n".getBytes(charset)).encode(certificate.getEncoded()), charset)
         + "\r\n-----END CERTIFICATE-----";
   }

   public static X509Certificate certificateFromPemString(String pemString) throws CertificateException, ParseException {
      CertificateFactory cf = CertificateFactory.getInstance("X.509");
      return (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(pemCertificateToDerCertificate(pemString)));
   }

   private static byte[] pemCertificateToDerCertificate(String pem) throws ParseException {
      StringBuilder buffy = new StringBuilder(pem.length());
      char[] pemChars = pem.toCharArray();

      for (char pemChar : pemChars) {
         if (!Character.isWhitespace(pemChar)) {
            buffy.append(pemChar);
         }
      }

      String pemObjectPrefix = "-----";
      String pemObjectSuffix = "-----";
      int b64Start = buffy.indexOf("-----");
      if (b64Start == -1) {
         throw new ParseException("PEM encoded object does not start with \"-----XXXX-----\".", 0);
      }

      b64Start = buffy.indexOf("-----", b64Start + "-----".length());
      if (b64Start == -1) {
         throw new ParseException("PEM encoded object does not start with \"-----XXXX-----\".", 0);
      }

      b64Start += "-----".length();
      int b64End = buffy.indexOf("-----", b64Start + 1);
      if (b64End == -1) {
         throw new ParseException("PEM encoded certificate does not end with \"-----XXXX-----\".", 0);
      }

      String b64 = buffy.substring(b64Start, b64End);
      return Base64.getDecoder().decode(b64);
   }
}
