package com.vaklinov.zcashui;

import java.awt.Component;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.ProgressMonitorInputStream;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

/**
 * Fetches the proving key.  Deliberately hardcoded.
 * @author zab
 */
public class ProvingKeyFetcher {
    
    
    private static final int PROVING_KEY_SIZE = 910173851;
    private static final String SHA256 = "8bc20a7f013b2b58970cddd2e7ea028975c88ae7ceb9259a5344a16bc2c0eef7";
    private static final String URL = "https://zcash.dl.mercerweiss.com/sprout-proving.key";
    // TODO: add backups
    
    public void fetchIfMissing(Component parent) throws IOException,InterruptedException {
        File zCashParams = new File(System.getProperty("user.home") + "/Library/Application Support/ZcashParams");
        zCashParams = zCashParams.getCanonicalFile();
        
        boolean needsFetch = false;
        if (!zCashParams.exists()) {
            needsFetch = true;
            zCashParams.mkdirs();
        }
        
        // verifying key is small, always copy it
        File verifyingKeyFile = new File(zCashParams,"sprout-verifying.key");
        FileOutputStream fos = new FileOutputStream(verifyingKeyFile);
        InputStream is = ProvingKeyFetcher.class.getClassLoader().getResourceAsStream("sprout-verifying.key");
        copy(is,fos);
        fos.close();
        
        File provingKeyFile = new File(zCashParams,"sprout-proving.key");
        provingKeyFile = provingKeyFile.getCanonicalFile();
        if (!provingKeyFile.exists())
            needsFetch = true;
        else if (provingKeyFile.length() != PROVING_KEY_SIZE)
            needsFetch = true;
        else {
            needsFetch = !checkSHA256(provingKeyFile);
        }
        
        if (!needsFetch) 
            return;
        
        JOptionPane.showMessageDialog(parent, "Zcash needs to download a large file.  This will happen only once.\n  "
                + "Please be patient.  Press OK to continue");
        
        provingKeyFile.delete();
        OutputStream os = new BufferedOutputStream(new FileOutputStream(provingKeyFile));
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet get = new HttpGet(URL);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(get);
            is = response.getEntity().getContent();
            ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(parent, "Downloading proving key", is);
            pmis.getProgressMonitor().setMaximum(PROVING_KEY_SIZE);
            pmis.getProgressMonitor().setMillisToPopup(10);
            copy(pmis,os);
            os.close();
        } catch (InterruptedIOException cancelled) {
            JOptionPane.showMessageDialog(null, "Zcash cannot proceed without a proving key.");
            System.exit(-3);
        } finally {
            try {if (response != null)response.close();} catch (IOException ignore){}
            try {httpClient.close();} catch (IOException ignore){}
        }
        if (!checkSHA256(provingKeyFile)) {
            JOptionPane.showMessageDialog(parent, "Failed to download proving key.  Cannot continue");
            System.exit(-4);
        }
    }
            

    private static void copy(InputStream is, OutputStream os) throws IOException {
        byte[] buf = new byte[0x1 << 13];
        int read;
        while ((read = is.read(buf)) >- 0) {
            os.write(buf,0,read);
        }
        os.flush();
    }
    
    private static boolean checkSHA256(File provingKey) throws IOException, InterruptedException {
        CommandExecutor executor = new CommandExecutor(new String[]
                {"shasum","-a","256",provingKey.getCanonicalPath()});
        String sum = executor.execute();
        return sum.startsWith(SHA256);
    }
}

@@ -47,24 +47,60 @@
 .Component;%0A
+import java.io.BufferedInputStream;%0A
 import java.
@@ -145,16 +145,48 @@
 o.File;%0A
+import java.io.FileInputStream;%0A
 import j
@@ -330,25 +330,24 @@
 tputStream;%0A
-%0A
 import javax
@@ -349,22 +349,71 @@
 java
-x
 .s
-wing.JFrame
+ecurity.DigestInputStream;%0Aimport java.security.MessageDigest
 ;%0Aim
@@ -425,28 +425,44 @@
 java
-x
 .s
-wing.JOptionPane;
+ecurity.NoSuchAlgorithmException;%0A
 %0Aimp
@@ -482,19 +482,18 @@
 ng.J
-ProgressBar
+OptionPane
 ;%0Aim
@@ -541,50 +541,49 @@
 am;%0A
-%0A
 import 
-org.apache.http.client.HttpClient;
+javax.xml.bind.DatatypeConverter;%0A
 %0Aimp
@@ -1273,29 +1273,8 @@
 tion
-,InterruptedException
  %7B%0A 
@@ -4198,168 +4198,478 @@
 tion
-, InterruptedException %7B%0A        CommandExecutor executor = new CommandExecutor(new String%5B%5D%0A                %7B%22shasum%22,%22-a%22,%22256%22,provingKey.getCanonicalPath()%7D
+ %7B%0A        MessageDigest sha256;%0A        try %7B%0A            sha256 = MessageDigest.getInstance(%22SHA-256%22);%0A        %7D catch (NoSuchAlgorithmException impossible) %7B%0A            throw new RuntimeException(impossible);%0A        %7D%0A        try (InputStream is = new BufferedInputStream(new FileInputStream(provingKey))) %7B%0A            DigestInputStream dis = new DigestInputStream(is, sha256);%0A            byte %5B%5D temp = new byte%5B0x1 %3C%3C 13%5D;%0A            while(dis.read(temp) %3E= 0
 );%0A 
@@ -4679,79 +4679,141 @@
     
+  
-String sum = executor.execute();%0A        return sum.startsWith(SHA256);
+  byte %5B%5D digest = sha256.digest();%0A            return SHA256.equalsIgnoreCase(DatatypeConverter.printHexBinary(digest));%0A        %7D
 %0A   

use java sha256