From 8c16d586114dc9156386f0b4bdc6c42d7a0e31fb Mon Sep 17 00:00:00 2001
From: Ziggy Jonsson <ziggy.jonsson.nyc@gmail.com>
Date: Sun, 12 May 2024 09:15:19 -0400
Subject: [PATCH] fix js errors

---
 .github/workflows/test.yml |  1 +
 .gitignore                 |  1 -
 jsconfig.json              |  4 ++--
 lib/Decrypt.js             |  7 +++++--
 lib/NoopStream.js          | 18 ++++++++----------
 lib/extract.js             |  1 +
 lib/parse.js               | 30 ++++++++++++++++++++----------
 lib/parseExtraField.js     |  4 +---
 lib/parseOne.js            |  6 +++---
 package.json               |  3 ++-
 test/compressed-crx.js     |  8 +++++---
 test/office-files.js       |  4 ++--
 test/streamSingleEntry.js  |  2 +-
 test/uncompressed.js       |  4 ++--
 14 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index eefdaf4..1fd3b41 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -19,6 +19,7 @@ jobs:
           node-version: 18.x
       - run: npm install
       - run: npx eslint .
+      - run: npx tsc -p jsconfig.json
 
   test:
     runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index ed57018..97223ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
 /.idea
 /node_modules
-/test.js
 /.nyc_output/
 /coverage/
 .tap/
diff --git a/jsconfig.json b/jsconfig.json
index 1c2fef5..e7d635f 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -3,11 +3,11 @@
     "checkJs": true,
     "target": "ES2022",
     "moduleResolution":"node",
-    "types": ["node"]
+    "types": ["node"],
+    "maxNodeModuleJsDepth": 0,
   },
   "exclude": [
     "node_modules",
-    "test",
     "coverage"
   ]
 }
\ No newline at end of file
diff --git a/lib/Decrypt.js b/lib/Decrypt.js
index 447d8af..ec4fb0a 100644
--- a/lib/Decrypt.js
+++ b/lib/Decrypt.js
@@ -21,7 +21,7 @@ function crc(ch, crc) {
 
   if (ch.charCodeAt)
     ch = ch.charCodeAt(0);
-
+  //@ts-ignore
   return (bigInt(crc).shiftRight(8).and(0xffffff)).xor(table[bigInt(crc).xor(ch).and(0xff)]).value;
 }
 
@@ -36,7 +36,9 @@ function Decrypt() {
 
 Decrypt.prototype.update = function(h) {
   this.key0 = crc(h, this.key0);
+  //@ts-ignore
   this.key1 = bigInt(this.key0).and(255).and(4294967295).add(this.key1);
+  //@ts-ignore
   this.key1 = bigInt(this.key1).multiply(134775813).add(1).and(4294967295).value;
   this.key2 = crc(bigInt(this.key1).shiftRight(24).and(255), this.key2);
 };
@@ -44,13 +46,14 @@ Decrypt.prototype.update = function(h) {
 
 Decrypt.prototype.decryptByte = function(c) {
   const k = bigInt(this.key2).or(2);
+  //@ts-ignore
   c = c ^ bigInt(k).multiply(bigInt(k^1)).shiftRight(8).and(255);
   this.update(c);
   return c;
 };
 
 Decrypt.prototype.stream = function() {
-  const stream = Stream.Transform(),
+  const stream = new Stream.Transform(),
     self = this;
 
   stream._transform = function(d, e, cb) {
diff --git a/lib/NoopStream.js b/lib/NoopStream.js
index 98c05f8..d28dfc2 100644
--- a/lib/NoopStream.js
+++ b/lib/NoopStream.js
@@ -1,14 +1,12 @@
 const Stream = require('stream');
-const util = require('util');
-function NoopStream() {
-  if (!(this instanceof NoopStream)) {
-    return new NoopStream();
-  }
-  Stream.Transform.call(this);
+class NoopStream extends Stream.Transform {
+  _transform(d, e, cb) { cb() ;};
+  promise() {
+    return new Promise((resolve, reject) => {
+      this.on('finish', resolve);
+      this.on('error', reject);
+    });
+  };
 }
 
-util.inherits(NoopStream, Stream.Transform);
-
-NoopStream.prototype._transform = function(d, e, cb) { cb() ;};
-
 module.exports = NoopStream;
\ No newline at end of file
diff --git a/lib/extract.js b/lib/extract.js
index 31d725a..8100c34 100644
--- a/lib/extract.js
+++ b/lib/extract.js
@@ -1,3 +1,4 @@
+//@ts-nocheck
 module.exports = Extract;
 
 const Parse = require('./parse');
diff --git a/lib/parse.js b/lib/parse.js
index 1b35cf7..4f14015 100644
--- a/lib/parse.js
+++ b/lib/parse.js
@@ -11,7 +11,23 @@ const parseBuffer = require('./parseBuffer');
 const endDirectorySignature = Buffer.alloc(4);
 endDirectorySignature.writeUInt32LE(0x06054b50, 0);
 
+class Entry extends Stream.PassThrough{
+  autodrain;
+  buffer;
+  path;
+  props;
+  CSSFontFeatureValuesRule;
+  type;
+  extra;
+  size;
+  vars;
+  __autodraining;
+}
+
+
 class Parse extends PullStream {
+  reachedCD;
+  crxHeader;
   constructor(opts) {
     super(opts || { verbose: false });
     const self = this;
@@ -105,18 +121,12 @@ class Parse extends PullStream {
 
       return self.pull(vars.fileNameLength).then(function(fileNameBuffer) {
         const fileName = fileNameBuffer.toString('utf8');
-        const entry = Stream.PassThrough();
+        const entry = new Entry();
         let __autodraining = false;
 
         entry.autodrain = function() {
           __autodraining = true;
-          const draining = entry.pipe(NoopStream());
-          draining.promise = function() {
-            return new Promise(function(resolve, reject) {
-              draining.on('finish', resolve);
-              draining.on('error', reject);
-            });
-          };
+          const draining = entry.pipe(new NoopStream());
           return draining;
         };
 
@@ -155,7 +165,7 @@ class Parse extends PullStream {
             self.push(entry);
           } else {
             self.emit('entry', entry);
-
+            //@ts-ignore
             if (self._readableState.pipesCount || (self._readableState.pipes && self._readableState.pipes.length))
               self.push(entry);
           }
@@ -171,7 +181,7 @@ class Parse extends PullStream {
           let eof;
 
           entry.__autodraining = __autodraining; // expose __autodraining for test purposes
-          const inflater = (vars.compressionMethod && !__autodraining) ? zlib.createInflateRaw() : Stream.PassThrough();
+          const inflater = (vars.compressionMethod && !__autodraining) ? zlib.createInflateRaw() : new Stream.PassThrough();
 
           if (fileSizeKnown) {
             entry.size = vars.uncompressedSize;
diff --git a/lib/parseExtraField.js b/lib/parseExtraField.js
index 42d178f..6f4b16a 100644
--- a/lib/parseExtraField.js
+++ b/lib/parseExtraField.js
@@ -1,7 +1,7 @@
 const parseBuffer = require('./parseBuffer');
 
 module.exports = function(extraField, vars) {
-  let extra;
+  let extra = {};
   // Find the ZIP64 header, if present.
   while(!extra && extraField && extraField.length) {
     const candidateExtra = parseBuffer.parse(extraField, [
@@ -22,8 +22,6 @@ module.exports = function(extraField, vars) {
     }
   }
 
-  extra = extra || {};
-
   if (vars.compressedSize === 0xffffffff)
     vars.compressedSize = extra.compressedSize;
 
diff --git a/lib/parseOne.js b/lib/parseOne.js
index 275dde0..322220a 100644
--- a/lib/parseOne.js
+++ b/lib/parseOne.js
@@ -4,9 +4,9 @@ const duplexer2 = require('duplexer2');
 const BufferStream = require('./BufferStream');
 
 function parseOne(match, opts) {
-  const inStream = Stream.PassThrough({objectMode:true});
-  const outStream = Stream.PassThrough();
-  const transform = Stream.Transform({objectMode:true});
+  const inStream = new Stream.PassThrough({objectMode:true});
+  const outStream = new Stream.PassThrough();
+  const transform = new Stream.Transform({objectMode:true});
   const re = match instanceof RegExp ? match : (match && new RegExp(match));
   let found;
 
diff --git a/package.json b/package.json
index 9f20cf8..82b944b 100644
--- a/package.json
+++ b/package.json
@@ -30,9 +30,10 @@
     "graceful-fs": "^4.2.2"
   },
   "devDependencies": {
+    "typescript": "^5.4.5",
     "@eslint/js": "^9.2.0",
-    "@types/node": "^20.12.11",
     "@types/bluebird": "^3.5.42",
+    "@types/node": "^20.12.11",
     "aws-sdk": "^2.77.0",
     "dirdiff": ">= 0.0.1 < 1",
     "eslint": "^9.2.0",
diff --git a/test/compressed-crx.js b/test/compressed-crx.js
index 865567e..2102717 100644
--- a/test/compressed-crx.js
+++ b/test/compressed-crx.js
@@ -42,17 +42,19 @@ test('open methods', async function(t) {
   const s3 = new AWS.S3({region: 'us-east-1'});
 
   // We have to modify the `getObject` and `headObject` to use makeUnauthenticated
+  //@ts-ignore
   s3.getObject = function(params, cb) {
     return s3.makeUnauthenticatedRequest('getObject', params, cb);
   };
 
+  //@ts-ignore
   s3.headObject = function(params, cb) {
     return s3.makeUnauthenticatedRequest('headObject', params, cb);
   };
 
   const tests = [
-    {name: 'buffer', args: [buffer]},
-    {name: 'file', args: [archive]},
+    {name: 'buffer', args: [buffer, {crx: true}]},
+    {name: 'file', args: [archive, {crx: true}]},
     // {name: 'url', args: [request, 'https://s3.amazonaws.com/unzipper/archive.crx']},
     // {name: 's3', args: [s3, { Bucket: 'unzipper', Key: 'archive.crx'}]}
   ];
@@ -61,7 +63,7 @@ test('open methods', async function(t) {
     t.test(test.name, async function(t) {
       t.test('opening with crx option', function(t) {
         const method = unzip.Open[test.name];
-        method.apply(method, test.args.concat({crx:true}))
+        method.apply(method, test.args)
           .then(function(d) {
             return d.files[1].buffer();
           })
diff --git a/test/office-files.js b/test/office-files.js
index b0a9fe4..719791e 100644
--- a/test/office-files.js
+++ b/test/office-files.js
@@ -19,14 +19,14 @@ test("get content a xlsx file without errors", async function () {
 
 test("stream retries when the local file header indicates bigger size than central directory", async function (t) {
   const archive = path.join(__dirname, '../testData/office/testfile.xlsx');
-  let retries = 0, size;
+  let retries = 0, size = 0;
   const directory = await unzip.Open.file(archive, {padding: 10});
   const stream = directory.files[0].stream();
   stream.on('streamRetry', _size => {
     retries += 1;
     size = _size;
   });
-  await new Promise(resolve => stream.pipe(NoopStream()).on('finish', resolve));
+  await new Promise(resolve => stream.pipe(new NoopStream()).on('finish', resolve));
   t.ok(retries === 1, 'retries once');
   t.ok(size > 0, 'size is set');
 });
\ No newline at end of file
diff --git a/test/streamSingleEntry.js b/test/streamSingleEntry.js
index 9fc4466..6a319c3 100644
--- a/test/streamSingleEntry.js
+++ b/test/streamSingleEntry.js
@@ -6,7 +6,7 @@ const unzip = require('../');
 const Stream = require('stream');
 
 test("pipe a single file entry out of a zip", function (t) {
-  const receiver = Stream.Transform({objectMode:true});
+  const receiver = new Stream.Transform({objectMode:true});
   receiver._transform = function(entry, e, cb) {
     if (entry.path === 'file.txt') {
       const writableStream = new streamBuffers.WritableStreamBuffer();
diff --git a/test/uncompressed.js b/test/uncompressed.js
index 94af3fd..da113cc 100644
--- a/test/uncompressed.js
+++ b/test/uncompressed.js
@@ -63,7 +63,7 @@ test("do not extract zip slip archive", function (t) {
     fs.createReadStream(archive).pipe(unzipExtractor);
 
     function testNoSlip() {
-      const mode = fs.F_OK | (fs.constants && fs.constants.F_OK);
+      const mode = fs.constants.F_OK | (fs.constants && fs.constants.F_OK);
       return fs.access(path.join(os.tmpdir(), 'evil.txt'), mode, evilFileCallback);
     }
 
@@ -105,7 +105,7 @@ function testZipSlipArchive(t, slipFileName, attackPathFactory){
 
     function CheckForSlip(path, resultCallback) {
       const fsCallback = function(err){ return resultCallback(!err); };
-      const mode = fs.F_OK | (fs.constants && fs.constants.F_OK);
+      const mode = fs.constants.F_OK | (fs.constants && fs.constants.F_OK);
       return fs.access(path, mode, fsCallback);
     }