Search code examples
node.jsunzipzip

Unzipping a password protected file in Node.js


Is there a library that I can use to unzip a password protected file (Site makes me put a password on the file when downloading it)? There are a ton of libraries to unzip normal files, but none that I can find that will do it with a password.

Here I found some helpful starters. But I would rather not resort to using child_process and using built in unix unzipping functionality, but that may be my last resort. I would even be up to preforming my own manipulation on the encrypted code, but I'm unable to even find out how to determine the encryption type (it seems to just be very standard, since i can do it in the terminal).

Again I would rather not do this, but I'm afraid it is my only option so I have tried the following:

var fs = require('fs')
, unzip = require('unzip')
, spawn = require('child_process').spawn
, expand = function(filepath, cb) {
     var self = this
     , unzipStream = fs.createReadStream(filepath).pipe(unzip.Parse())
     , xmlData = '';

     unzipStream.on('entry', function (entry) {
            var filename = entry.path;
           // first zip contains files and one password protected zipfile. 
           // Here I can just do pipe(unzip.Parse()) again, but then i just get a giant encoded string that I don't know how to handle, so i tried other things bellow.
           if(filename.match(/\.zip$/)){
                 entry.on('data', function (data) {
                     var funzip = spawn('funzip','-P','ThisIsATestPsswd','-');
                     var newFile = funzip.stdin.write(data);

            // more closing code...

Then I sort of lost what to do. I tried writing newFile to a file, but that just said [object].

Then I tried just doing something simpler by changing the last 3 lines to

   fs.writeFile('./tmp/this.zip', data, 'binary');
   var newFile = spawn('unzip','-P','ThisIsATest','./tmp/this.zip');
   console.log('Data: ' + data);

But data isn't anything useful just [object Object] again. I can't figure out what to do next to get this new unzipped file into either a working file, or a readable string.

I am super new to Node and all the async/listeners being fired by other processes is a little confusing still, so I'm sorry if any of this makes no sense. Thanks so much for the help!

EDIT:


I have now added the following code:

var fs = require('fs')
  , unzip = require('unzip')
  , spawn = require('child_process').spawn
  , expand = function(filepath, cb) {
    var self = this
    , unzipStream = fs.createReadStream(filepath)
      .pipe(unzip.Parse())
    , xmlData = '';

      unzipStream.on('entry', function (entry) {
        var filename = entry.path
            , type = entry.type // 'Directory' or 'File'
            , size = entry.size;
        console.log('Filename: ' + filename);

        if(filename.match(/\.zip$/)){
            entry.on('data', function (data) {
              fs.writeFile('./lib/mocks/tmp/this.zip', data, 'binary');
              var newFile = spawn('unzip','-P','ThisIsATestPassword', '-','../tmp/this.zip');
              newFile.stdout.on('data', function(data){
                 fs.writeFile('./lib/mocks/tmp/that.txt', data); //This needs to be something different
                    //The zip file contains an archive of files, so one file name shouldn't work
              });

           });
          } else { //Not a zip so handle differently }
       )};
    };

This seems to be really close to what I need, but when the file is written all it has is the options list for unzip:

UnZip 5.52 of 28 February 2005, by Info-ZIP.  Maintained by C. Spieler.  Send
bug reports using http://www.info-zip.org/zip-bug.html; see README for details.

Usage: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
  Default action is to extract files in list, except those in xlist, to exdir;
  file[.zip] may be a wildcard.  -Z => ZipInfo mode ("unzip -Z" for usage).

  -p  extract files to pipe, no messages     -l  list files (short format)
  -f  freshen existing files, create none    -t  test compressed archive data
  -u  update files, create if necessary      -z  display archive comment
  -x  exclude files that follow (in xlist)   -d  extract files into exdir

modifiers:                                   -q  quiet mode (-qq => quieter)
  -n  never overwrite existing files         -a  auto-convert any text files
  -o  overwrite files WITHOUT prompting      -aa treat ALL files as text
  -j  junk paths (do not make directories)   -v  be verbose/print version info
  -C  match filenames case-insensitively     -L  make (some) names lowercase
  -X  restore UID/GID info                   -V  retain VMS version numbers
  -K  keep setuid/setgid/tacky permissions   -M  pipe through "more" pager
Examples (see unzip.txt for more info):
  unzip data1 -x joe   => extract all files except joe from zipfile data1.zip
  unzip -p foo | more  => send contents of foo.zip via pipe into program more
  unzip -fo foo ReadMe => quietly replace existing ReadMe if archive file newer

I'm not sure if the input was wrong since this looks like the error for unzip. Or if I am just writing the wrong content. I would have thought that it would just preform like it does normally from the console--just adding all files as they are extracted to the directory. while I would love to be able to just read all content from a buffer, the - option doesn't seem to do that and so I would settle for the files just being added to the directory. Thanks so much to anyone with any suggestions!

Edit 2


I was able to get this working, not the best way probably but it works at least using this line:

var newFile = spawn('unzip', [ '-P','ThisIsATestPassword', '-d','./lib/tmp/foo','./lib/mocks/tmp/this.zip' ])

This will just unzip all the files into the directory and then I was able to read them from there. My mistake was that the second parameter has to be an array.


Solution

  • I was able to get this working, not the best way probably but it works at least using this line:

    var newFile = spawn('unzip', [ '-P','ThisIsATestPassword', '-d','./lib/tmp/foo','./lib/mocks/tmp/this.zip' ])
    

    This will just unzip all the files into the directory and then I was able to read them from there. My mistake was that the second parameter has to be an array.