Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 727
CodySchaaf Avatar asked May 29 '14 06:05

CodySchaaf


People also ask

How do I unzip a password protected zip file in node?

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.

How do you Zip a file with password?

If you put the files you'd like to protect in a zip file, you can then apply a password. In Windows Explorer, highlight and right-click on the files you would like to put into a zipped file. Select Send to, then Zip folder (compressed). Double-click the zipped file, then select File and Add Password.

How do I password protect a zip file in Linux?

Create a Password-Protected ZIP File in Linux Using GUIStep 1: Go to the file location and right-click on the file. Step 2: Then click on the compress option. Step 3: Then click on the other option and set your password and click on Create option.


2 Answers

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.

like image 66
CodySchaaf Avatar answered Sep 24 '22 23:09

CodySchaaf


I found the solution using unzipper.

Pasting the code from this blog

const unzipper = require('unzipper');

(async () => {
  try {
    const directory = await unzipper.Open.file('path/to/your.zip');
    const extracted = await directory.files[0].buffer('PASSWORD');
    console.log(extracted.toString()); // This will print the file content
  } catch(e) {
    console.log(e);
  }
})();

As @codyschaaf mentioned in his answer, we can use spawn or some other child_process but they're not always OS agnostic. So if I'm using this in production, I'll always go for an OS-agnostic solution if it exists.

Hope this helps someone.

like image 43
Apal Shah Avatar answered Sep 24 '22 23:09

Apal Shah