Search code examples
javascriptfile-uploadcompressionjszipcryptico

JSZip compress image upload, encrypt, decrypt, display image


Initially I was using FileReader to convert an image upload into base64 on the client side and then encrypt. Would attach that result to a form field and then submit but this is taking up way too much time so I'm looking for an alternative.

I'm trying to use JSZip to first compress and then encrypt and then submit, retrieve, decrypt, and show the image but I'm stuck on how to do that. My attempt to compress looks like this.

$(document).on("change", "#chatImage", function() {
    var rid = $(this).closest(".chat").data("id");
    var tempSrc = $(this).val();
    /* Make a zip file here */
    var fi = $(this);
    var fileInput = fi;
    var files = [];
    // get all selected file
    $.each(fileInput.files, function(i, file) {
        files.push(file);
    });
    //create a zip object
    var zip = new JSZip();
    //add all files to zip 
    function addFileToZip(n) {
        if(n >= files.length) {
            //here generate file to zip on client side
            zip.generateAsync({type:"blob", compression:"default"}).then(function(content){
                //generated zip content to file type
                var files = new File([content], "default.zip");
                console.log(files);
                var eImgArray = {};
                $.ajax({
                    url : ajax_object.ajax_url,
                    type : 'post',
                    data : {
                    action: 'get_room_member_keys',
                    rid : rid,
                    },
                    beforeSend: function() {},
                    success: function(html) {
                        var pubKeys = $.parseJSON(html);
                        $.each( pubKeys, function( key, value ) {
                            var imgEncrypt = cryptico.encrypt(files, value);
                            var imgSrc = imgEncrypt.cipher;
                            eImgArray[key] = imgSrc;
                        });
                        var strImgArray = JSON.stringify(eImgArray);
                    },
                });
            });
            return;
        }
        var file = files[n];                    
        var arrayBuffer;
        var fileReader = new FileReader();
        fileReader.onload = function() {
            arrayBuffer = this.result;
            zip.file(file.name, arrayBuffer);
            addFileToZip(n + 1);
        }
        fileReader.readAsArrayBuffer(file);
    }
    addFileToZip(0);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<a id="jaj3dm" class="chat" />
<input id="chatImage" type="file" multiple="multiple" />

This shows an encrypted string in the console and the result of compressing but when I decrypt and log the result to the console, I get nothing. What is the correct way to do this and or a better one?


Solution

  • You've ridiculously overcomplicated this!

    $(document).on("change", "#chatImage", function() {
      var files = this.files;
      var zip = new JSZip();
    
      for (var i = 0; i < files.length; i += 1) {
        var file = files[i];
        zip.file(file.name, file);
    
        console.log("added", file.name);
      }
    
      console.log("generating zip…");
      zip.generateAsync({type: "blob"}).then(function(content) {
        console.log("done. creating download link");
    
        /* All that "sending to the interwebz" stuff */
        var link = document.createElement("a");
        link.href = window.URL.createObjectURL(content);
        link.innerText = "Download…";
        document.body.appendChild(link);
    
        /* display the uploaded images */
        function show_all_images(relpath, file) {
          console.log("showing", relpath);
          if (file.dir) {
            return file.forEach(show_all_images);
          }
          var img = document.createElement("img");
          img.alt = relpath;
          document.body.appendChild(img);
          file.async("blob").then(function(blob) {
            img.src = window.URL.createObjectURL(blob);
          });
        }
        new JSZip.loadAsync(content).then(zip => zip.forEach(show_all_images));
      });
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cryptico/0.0.1343522940/cryptico.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <input id="chatImage" type="file" multiple="multiple" />